模板:luogo p3379 【模板】最近公共祖先(lca)
今天講的時候有點跑神,現在卑微地來補習(菜)
lca指的是最近公共祖先(least common ancestors)。
最簡單的演算法無疑是從兩個點乙個個往上走,出現的第乙個兩個點都走過的點即為兩點的lca。
但是時間很長。
所以起用倍增,倍增的作用就是將兩點上公升所需的複雜度減低。
大致流程為:將deep不同的兩個點跳到同一層,再跳到deep[lca-1]的那層,再向上跳一層就是lca了。
加速跳的方法就是每次向上跳的層數為2的i次方層,就是把層數轉化成2進製的數,這樣時間複雜度就變為log2(n)了。
之後要兩個陣列f[i][j](從i向上2^j層後到達的點)和deep[i](這棵樹中i點的深度)。
deep[i]用乙個dfs求得。
f[i][j]用了遞推,f[i][j]=f[f[i][j-1]][j-1]。初始化f[i][0]也可以在遍歷整棵樹的時候求得。
然後,兩點再同時向上逼近。i從最高位開始列舉,假設兩點分別為x,y,那麼能向上跳的判斷式為:
if (f[x][i]!=f[y][i])
就是如果兩點向上跳了2^i層以後不到同乙個點就接著往上跳。為什麼這樣?因為如果往上跳了2^i層,即使到了同乙個點,它不一定是兩點的lca。
這樣做,最終就會到達lca的下面一層。隨後,我們再將兩點向上跳一層。lca求得。
然後這個讓我無比摸不著頭腦的問題出現了:
我們假設從a,b點開始,往上跳2^j層,跳到同一點。不跳。往上跳2^(j-1)層,不跳到同一點,往上跳,分別到了a',b'。顯然,這種情況是一定會存在的。那麼,從a',b』再往上跳到原來那個決定不跳的點,顯然要跳2^(j-1)層。那麼,那個點有可能是lca,也有可能不是,對吧?所以,從a',b'往上跳到lca所需的層數,是≤2^(j-1)的。換句話來說,a',b'到x的層數變成了乙個j-2位的二進位制數(可能會有前導零,也就是還可能會跳到點數相同的地方)。而此時,剛好列舉到j-2位。那麼,前導零不減,再這麼減下去,你發現,這個層數差最終會變成0,而你最終也會到達第x層。大概就是你的叔伯(爸爸的兄弟)不是你的祖先,這裡找的祖先必須是直系的。
首先我們證明,前導零不會被減去。假設與x層的層數差為x',而你正準備往上跳y層。由於lca的層數是x+1,而lca往上的點它都不會跳,對吧?(反而,如果lca往下的點,也就是層數<=x,也就是y=x'+1,那麼就絕對不會往上跳。顯然,當x'的該位為0,且屬於前導零,那麼只需證明x'+1<=y。而這個非常易證(假設y為10000,而x'滿足條件的最大值為01111)。所以保證,前導零是不會減去的。
接著我們證明,一旦列舉到了x'的第乙個為1的位數,這個1絕對會被減去。按照同樣的方法,假設y為10000,而x'滿足條件的最小值為10000,所以y
兩點合在一起,前導零不會減去,列舉到乙個1位就減去,最終這個層數差就會變成0.證畢。
#include#include#include
#include
#include
#define maxn 500010#include
using
namespace
std;
int f[maxn][21
],head[maxn],deep[maxn],cnt,n,m,rt;
struct
edge
e[maxn
<<1
];void add(int u,int
v)void dfs(int x,int
fa)}
void
init()}}
}int query(int x,int
y) }
return f[x][0];}
intmain()
dfs(rt,0);
init();
while(m--)
return0;
}
2019-07-3122:54:32
2023年7月訓練(壹)
2019 07 25 luogu p3627 apio2009 搶掠計畫 卡了三個小時,看了題解才作出來的 菜 前驅知識 壹 鄰接表儲存 遍歷 貳 spfa跑最長路 改 就行了 叄 tarjan縮點 壹.鄰接表儲存 兩個,add存無邊權,未縮點 build有邊權,已縮點。void add int u...
2023年7月24日訓練日記
早上去了討論了一下昨天的b題,其實莫隊也挺好理解的,那道題直接套板子就能過,然後昨天那個二十幾行的 也理解了,思路特別巧妙,和我之前的思路差不多,只不過我少考慮了乙個點。然後上午看了一下字首和,字首和在應用中有不少技巧,不單單是對資料求和,還可以和平均數求差後求和。然後就是幾種排序,選擇排序,插入排...
2023年7月29日訓練日記
上午把昨天下午比賽的題補完了,這幾道題真是一言難盡,不難但是誰能想到啊,說明還是見的少。知識面廣的輕鬆ak。然後上午看了佇列,學了以前沒學過的雙端佇列,雙端佇列和vector差不多,就是有兩個介面,vector只能從隊尾新增,deque可以從兩端新增,功能也多了點。下午刷了幾道佇列的題,有一道以前s...