voiddfs(int pre,int x,int step){depth[x]= step;first[x]= cnt;tree[cnt]= x;cnt++;int len = g[x].size();for(int i =0; i < len;++i){if(g[x][i]== pre)continue;dfs(x, g[x][i], step +1);tree[cnt++]= x;}return;}intMin(int a,int b){if(depth[a]< depth[b])return a;elsereturn b;}voidRMQ(){for(int i =1; i <= cnt;++i){dp[i][0]= tree[i];}for(int i =1;(1<< i)<= cnt;++i){for(int j =1; j +(1<< i)-1<= cnt;++j){dp[j][i]=Min(dp[j][i -1], dp[j +(1<<(i -1))][i -1]);}}}intLCA(int a,int b){int l = first[a];int r = first[b];if(l > r)swap(l, r);int len =log2(r - l +1);returnMin(dp[l][len], dp[r -(1<< len)+1][len]);}
樹上倍增
father[ i ] [ j ]表示 i 的第 2 ^ j 個父親
dfs dfs在處理深度的同時更新每個人的father數組
voiddfs(int pre,int x){// 更新fatherfor(int i =1; i <=log2(n);++i){if(fa[x][i -1]==0)break;fa[x][i]= fa[fa[x][i -1]][i -1];}// 記錄深度depth[x]= depth[pre]+1;int len = g[x].size();for(int i =0; i < len;++i){int son = g[x][i];if(son == pre)continue;fa[son][0]= x;dfs(x, son);}}
LCA 首先將兩個節點的深度調成一樣,如果深度相同而且是同一個點就找到最近的祖先了,如果深度相同但是節點不同,這時就要向上倍增,需要注意的是倍增的中止條件不是兩個節點相同,而是節點的父親相同。因為每次倍增的范圍很大,很可能超過最近公共祖先,我們可以從最大的祖先開始,如果祖先相同縮小范圍,如果祖先不同更新兩個點的狀態繼續找,最后兩個人的最近公共祖先一定是father[ i ][ 0 ]
intLCA(int a,int b){if(depth[a]< depth[b])swap(a, b);int depth_x = depth[a]- depth[b];// 先將兩個點的深度調成一樣for(int i =0; i <=log2(depth_x);++i){if(depth_x &(1<< i))a = fa[a][i];}// 如果深度一樣,而且相同直接返回if(a == b)return a;// 從最遠的父親開始for(int i =log2(depth[a]); i >=0;--i){// 如果父親不同就向上更新if(fa[a][i]!= fa[b][i]){a = fa[a][i];b = fa[b][i];}}return fa[a][0];}
Tarjan
完美結合并查集和dfs 在**O(n + q)**解決LCA問題。 dfs的時候需要做以下處理:
對于當前點x來說:如果存在詢問(x,y),而且y已經dfs訪問過,那么LCA就是 find(y)
回溯的時候要將son的祖先設置為x(子樹的祖先始終為根節點)
int n;
LL dp[maxn], ans[maxn];int pre[maxn], vis[maxn];struct ac{int v, d;};
vector<ac> G[maxn], Q[maxn];intfind(int x){return x == pre[x]? x : pre[x]=find(pre[x]);}voidTarjan(int fa,int x){vis[x]=1;// 更新詢問for(auto it : Q[x]){if(!vis[it.v])continue;ans[it.d]= dp[x]+ dp[it.v]-2* dp[find(it.v)];}for(auto it : G[x]){if(it.v == fa)continue;dp[it.v]= dp[x]+ it.d;Tarjan(x, it.v);pre[it.v]= x;// 更新祖先}// for (int i = 0; i < (int)Q[x].size(); ++i) {// if (!vis[ Q[x][i].v ]) continue;// ans[ Q[x][i].d ] = dp[x] + dp[ Q[x][i].v ] - 2 * dp[find( Q[x][i].v )];// }// for (int i = 0; i < (int)G[x].size(); ++i) {// int son = G[x][i].v;// if (son == fa) continue;// dp[ G[x][i].v ] = dp[x] + G[x][i].d;// Tarjan(x, son);// pre[ G[x][i].v ] = x; // }}