呃,这个常用但是我一直不会
Tarjan
Tarjan 算法基于 dfs ,在 dfs 的过程中,对于每个节点位置的询问做出相应的回答。
dfs 的过程中,当一棵子树被搜索完成之后,就把他和他的父亲合并成同一集合;在搜索当前子树节点的询问时,如果该询问的另一个节点已经被访问过,那么该编号的询问是被标记了的,于是直接输出当前状态下,另一个节点所在的并查集的祖先;如果另一个节点还没有被访问过,那么就做下标记,继续 dfs 。
//tarjian,边建边 边回答问题 #include<cstdio> #include<cstdlib> #include<vector> using namespace std; int n,m,rt; const int N=500003,M=500003; int ans[M]; vector <int> e[N]; struct node { int v,id; node(int vv,int ii) { v=vv,id=ii; } node(){} }; vector <node> q[N]; int fa[N]; int find(int x) { return fa[x]==0?x:fa[x]=find(fa[x]); } bool vis[N]; void dfs(int x,int f) { int sz=e[x].size(); for(int i=0;i<sz;i++) { int v=e[x][i]; if(v!=f) dfs(v,x),fa[v]=x; } vis[x]=true; sz=q[x].size(); for(int i=0;i<sz;i++) { int v=q[x][i].v ; if(!ans[q[x][i].id ] && vis[v]) ans[q[x][i].id ]=find(v); } } int main() { scanf("%d%d%d",&n,&m,&rt); int u,v; for(int i=1;i<n;i++) scanf("%d%d",&u,&v),e[u].push_back(v),e[v].push_back(u); for(int i=0;i<m;i++) scanf("%d%d",&u,&v),q[u].push_back(node(v,i)),q[v].push_back(node(u,i)); dfs(rt,0); for(int i=0;i<m;i++) printf("%d ",ans[i]); return 0; }
倍增
就从父亲更新到儿子
#include<cstdio> #include<cstdlib> #include<vector> #include<algorithm> using namespace std; int n,q; const int N=100003,Q=10003; int fa[N][21],dep[N];//辅助数组dep vector <int > g[N]; bool tag[N]; void dfs(int x) { dep[x]=dep[fa[x][0]]+1; for(int i=1;i<21;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; int sz=g[x].size() ; for(int i=0;i<sz;i++) dfs(g[x][i]); } int lg[N]; void get_log() { for(int i=1;i<n;i++) lg[i]=lg[i-1]+(i==(1<<(lg[i-1])));//这里是看最高位,是第几位(第一位表示二进制中第0位) } int LCA(int u,int v) { if(dep[u]<dep[v]) swap(u,v); int dis=dep[u]-dep[v]; for(int i=1,j=0;dis;i<<=1,j++) if(dis&i) { dis^=i; u=fa[u][j]; } if(u==v) return u; for(int i=lg[dep[u]]-1;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; return fa[u][0]; } int main() { scanf("%d",&n); int u,v; for(int i=1;i<n;i++) scanf("%d%d",&u,&v),fa[v][0]=u,g[u].push_back(v),tag[v]=true; for(int i=1;i<=n;i++) if(!tag[i]) { dfs(i); break; } get_log(); scanf("%d",&q); while(q--) { scanf("%d%d",&u,&v); printf("%d ",LCA(u,v)); } return 0; }