倍增LCA 板子題 還是 hdu 2856 how far away 【個人感覺無比詳細】 > <
阿新 • • 發佈:2018-11-15
之前擼了一發離線的lca 就是tarjan演算法
這次來一發倍增lca
對於兩個節點的lca 這兩個節點要到同層 再跳躍倍增找到祖先
其本質是跳躍 2^i ==2^(i-1)+2^(i-1)
文字表述是我跳到八代祖先 我就先跳到四代祖先 再跳四代祖先
#include<cstring> #include<cstdio> #include<vector> #include<iostream> #include<algorithm> #include<cmath> using namespace std; const int maxn=40020; int dis[maxn];//根到子節點的距離 int depth[maxn];//每個節點的深度 int p[maxn][20]; int n,m; struct node { int to,value; }; vector<node> vec[maxn]; void dfs(int u,int step,int father) { //標個粑粑 順便把節點搜尋出來 depth[u]=step; p[u][0]=father; for(int i=0;i<vec[u].size();i++) { int v=vec[u][i].to; int w=vec[u][i].value; if(v!=father) { dis[v]=dis[u]+w; dfs(v,step+1,u); } } } void init_f() { for(int i=1;(1<<i)<=n;++i)//初始化到最壞情況 就是所有子節點都在一側 { for(int j=1;j<=n;++j) { p[j][i]=p[p[j][i-1]][i-1]; } } } /*int lca(int u,int v) { if(u==v) return u; if(depth[u]<depth[v]) swap(u,v); int d=depth[u]-depth[v]; for(int i=0;(1<<i)<=d;i++) { if((1<<i)&d) u=p[u][i]; } for(int i=(int)log2(n);i>=0;i--) { if(p[u][i]!=p[v][i]) { u=p[u][i]; v=p[v][i]; } } return p[u][0]; }*/ int lca(int u,int v) { if(depth[u]<depth[v]) swap(u,v); int d=depth[u]-depth[v]; for(int j=19;j>=0;--j){ if((1<<j)&d) //當d為3(11) 1<<j 為 10 就可以跳此時j為1. 當j為0時 1<<j 為1 就總共跳了3次 //Q:為毛不會重複跳躍同樣的次數 如:當d為(1xx)時,跳6下(110) 和4下(100)都會進入if啊? //A:他這是跳完之後就直接把這個二進位制位直接移走了呀 所以不會重複跳 u=p[u][j]; } /* 之前這一段 我想的跳到同層的操作是 for(int i=0;(1<<i)<=d;i++) if((1<<j)&d) u=p[u][j]; 但其實是錯誤的 從1開始起跳 假如我要跳到上八代祖先是永遠也不可能實現的 因為它是這樣跳的嘛 1 2 4 8 奇數只有一個 根本湊不到8 */ if(u==v){ return u; } for(int i=(int)log2(n);i>=0;--i){//這裡的logn是最壞情況 即所有元素都在樹的一側 if(p[u][i]!=p[v][i]){ //所以直接從高位起跳 加速 //Q:跳過頭了咋辦 //A:跳過頭的元素值是相同的 進不了if 所有u v不會更新 //Q:敲裡嗎 為毛元素是相同的 博主你快講清楚 //A:init_f裡 假如設根節點為第0層 第一層的節點假如跳兩下就過頭了 //那麼p[x][1]=p[p[x][0]][0] 其值還是根節點的父親 無論跳多少次都是根節點的父親 u=p[u][i]; v=p[v][i]; //所以u v的值始終不同 但會隨著程式的執行接近lca } } return p[u][0]; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { vec[i].clear(); } for(int i=0;i<n-1;i++) { node tem; int u,v,w; scanf("%d%d%d",&u,&v,&w); tem.to=v; tem.value=w; vec[u].push_back(tem); tem.to=u; vec[v].push_back(tem); } dis[1]=0; dfs(1,0,0); init_f(); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); int ans=dis[u]+dis[v]-2*dis[lca(u,v)]; printf("%d\n",ans); } } }