LCA(最近公共祖先)
阿新 • • 發佈:2020-08-10
LCA
\(LCA\)=最近公共祖先。
1.初始化\(lg\)陣列,其代表\(lg2+1\)。
2.利用倍增的思想去求\(fa[u][i]\),在\(u\)點向上走\(2^i\)步時的祖先是誰。深度\(dep\)也同時求出。
3.初始化\(fa[u][0]=father\)
4.\(LCA\)
int LCA(int x,int y){ if(dep[x]<dep[y]) swap(x,y); while(dep[x]>dep[y]){ x=fa[x][lg[dep[x]-dep[y]]-1];//一直跳直到深度相同 } if(x==y)return x; for(int k=lg[dep[x]]-1;k>=0;--k){ if(fa[x][k]!=fa[y][k])//向上跳從大->小,第一個不相等的點就是公共祖先的兒子 x=fa[x][k],y=fa[y][k]; } return fa[x][0];
P3379 【模板】最近公共祖先(LCA)
#include<bits/stdc++.h> using namespace std; //#define int long long int n,m,s; const int maxn=5e5+10; int head[maxn],tot=0; struct edge{ int to,next; }edge[maxn<<1]; void add(int u,int v){ edge[++tot].to=v; edge[tot].next=head[u]; head[u]=tot; } int dep[maxn],fa[maxn][22],lg[maxn]; void dfs(int u,int father){ dep[u]=dep[father]+1; fa[u][0]=father; for(int i=1;i<=lg[dep[u]];++i){ fa[u][i]=fa[fa[u][i-1]][i-1]; } for(int i=head[u];i;i=edge[i].next){ int v=edge[i].to; if(v==father)continue; dfs(v,u); } } int LCA(int x,int y){ if(dep[x]<dep[y]) swap(x,y); while(dep[x]>dep[y]){ x=fa[x][lg[dep[x]-dep[y]]-1]; } if(x==y)return x; for(int k=lg[dep[x]]-1;k>=0;--k){ if(fa[x][k]!=fa[y][k]) x=fa[x][k],y=fa[y][k]; } return fa[x][0]; } signed main(){ ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>n>>m>>s; for(int i=1;i<n;++i){ int x,y;cin>>x>>y; add(x,y);add(y,x); } for(int i=1;i<maxn;++i){ lg[i]=lg[i-1]+(1<<lg[i-1]==i); } dfs(s,0); for(int i=1;i<=m;++i){ int a,b;cin>>a>>b; cout<<LCA(a,b)<<endl; } }
P4281[AHOI2008]緊急集合、聚會
思路
求三個點的\(lca\),\(xy,xz,yz\)。我們容易知道的是必有兩個\(lca\)是相等的(畫圖易得),然後我們選擇不相等的那個\(lca\)作為最終的終點可。(畫圖易得)
#include<bits/stdc++.h> using namespace std; //#define int long long int n,m,s; const int maxn=5e5+10; int head[maxn],tot=0; struct edge{ int to,next; }edge[maxn<<1]; void add(int u,int v){ edge[++tot].to=v; edge[tot].next=head[u]; head[u]=tot; } int dep[maxn],fa[maxn][22],lg[maxn]; void dfs(int u,int father){ dep[u]=dep[father]+1; fa[u][0]=father; for(int i=1;i<=lg[dep[u]];++i){ fa[u][i]=fa[fa[u][i-1]][i-1]; } for(int i=head[u];i;i=edge[i].next){ int v=edge[i].to; if(v==father)continue; dfs(v,u); } } int LCA(int x,int y){ if(dep[x]<dep[y]) swap(x,y); while(dep[x]>dep[y]){ x=fa[x][lg[dep[x]-dep[y]]-1]; } if(x==y)return x; for(int k=lg[dep[x]]-1;k>=0;--k){ if(fa[x][k]!=fa[y][k]) x=fa[x][k],y=fa[y][k]; } return fa[x][0]; } signed main(){ // ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); //cin>>n>>m; scanf("%d%d",&n,&m); for(int i=1;i<n;++i){ int x,y; scanf("%d%d",&x,&y); add(x,y);add(y,x); } for(int i=1;i<maxn;++i){ lg[i]=lg[i-1]+(1<<lg[i-1]==i); } dfs(1,0); for(int i=1;i<=m;++i){ int x,y,z; // cin>>x>>y>>z; scanf("%d%d%d",&x,&y,&z); int xy=LCA(x,y),xz=LCA(x,z),yz=LCA(y,z); int ans; if(xy==xz){ ans=dep[x]+dep[y]+dep[z]-dep[yz]-dep[yz]-dep[xz]+dep[yz]-dep[xz]; printf("%d %d\n",yz,ans); // cout<<yz<<" "<<ans<<endl; }else if(xy==yz){ ans=dep[x]+dep[y]+dep[z]-dep[xz]-dep[xz]-dep[xy]+dep[xz]-dep[yz]; printf("%d %d\n",xz,ans); }else{ ans=dep[x]+dep[y]+dep[z]-dep[xy]-dep[xy]-dep[xz]+dep[xy]-dep[xz]; printf("%d %d\n",xy,ans); } } }