LCA演算法 線上樹上倍增模板
阿新 • • 發佈:2018-12-10
測試資料
1 10 1
1 2 2
1 4 4
2 3 3
2 5 6
3 7 1
3 8 2
5 6 3
6 9 2
4 10 4
9 10
終於造了什麼事樹上倍增了下午考pat。。。哭卿卿
程式碼理解來自 自己又加了備註。。。。 建議模擬一下
https://blog.csdn.net/a601025382s/article/details/10615039
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<bits/stdc++.h> using namespace std; const int maxn=40004; struct node{ int to,w; node(int a=0,int b = 0){to=a;w=b;} }; vector<node>e[maxn]; int f[maxn],dis[maxn],deep[maxn],p[maxn][20],n; void dfs(int u,int pre,int t) { int i,num; deep[u]=t;//深度 f[u]=pre;//父節點 num=e[u].size(); for(i=0;i<num;i++) { int v=e[u][i].to; if(v!=pre) { dis[v]=dis[u]+e[u][i].w;//距離跟的距離 dfs(v,u,t+1); } } } void init() { //p[i][j]表示i結點的第2^j祖先 int i, j; for(j = 1;(1 << j) <= n; j++) for(i = 1;i <= n; i++) p[i][j] = -1; //都初始化為-1 for(i = 1;i <= n; i++) p[i][0] = f[i]; for(j = 1;(1<<j) <= n;j ++) { for(i = 1;i <= n; i++) { if(p[i][j-1] != -1) p[i][j] = p[p[i][j-1]][j-1];//i的第2^j祖先就是i的第2^(j-1)祖先的第2^(j-1)祖先 } } } int lca(int a,int b)//最近公共祖先 { int i,j; if(deep[a] < deep[b]) swap(a,b); for(i = 0;(1 << i) <= deep[a]; i++); i--;//其實小於也行等於也好 //使a,b兩點的深度相同 for(j = i;j >= 0;j--) { if(deep[a]-(1<<j)>=deep[b]) { a = p[a][j]; } } //找到與b同層的或者說 b沒有同層的 那麼就找他的上一層 不用擔心p[a][j]是否等於-1 肯定有 if(a == b) return a; //倍增法,每次向上進深度2^j,找到最近公共祖先的子結點 for(j = i;j >= 0; j--) { if(p[a][j] != -1 && p[a][j] != p[b][j]) { a = p[a][j]; b = p[b][j]; } } /*如果說都是相等的話 那麼說明a b在兩個子樹的左右子樹下面 所以直接返回一個子樹的根節點就行 如果說是有不相等的話 那麼就兩個節點各自更新成他們的p[a][j] 和 p[b][j] */ return f[a]; } int main() { int m,i,a,b,c,ans; scanf("%d%d",&n,&m); for(i=1;i<=n;i++)e[i].clear(); for(i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); e[a].push_back(node(b,c)); e[b].push_back(node(a,c)); } dis[1]=0; dfs(1,-1,0);//找到各點的深度和各點的父節點以及距離根的距離 // cout<<"dis"<<endl; // for(int i = 0 ; i <= n ; i ++) // printf("%d%c",dis[i]," \n"[i==n]); // cout<<"deep"<<endl; // for(int i = 0 ; i <= n ; i ++) // printf("%d%c",deep[i]," \n"[i==n]); // cout<<"f"<<endl; // for(int i = 0 ; i <= n ; i ++) // printf("%d%c",f[i]," \n"[i==n]); init(); //初始各個點的2^j祖先是誰 for(i=0;i<m;i++) { scanf("%d%d",&a,&b); cout<<lca(a,b)<<endl; } return 0; } /* 最近公共祖先lca,線上演算法/倍增法,模板題。套別人模板自己敲了遍,現在還要回顧下鄰接表,哎。。 用vector,發現爆棧了,汗一個。。 用#pragma comment(linker, "/STACK:1024000000,1024000000") 開個把棧開大點吧。。hdu可以,別的地方就不清楚了 */ /* 1 10 7 1 2 2 1 4 4 2 3 3 2 5 6 3 7 1 3 8 2 5 6 3 6 9 2 4 10 4 */