树链剖分
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=5e5+10;int h[N],e[2*N],ne[2*N],idx=0;
void add(int u,int v){e[idx]=v,ne[idx]=h[u],h[u]=idx++;return;}int siz[N],de[N],son[N],top[N],fa[N],id[N],num;
void dfs1(int u,int f) //一次dfs求出深度,父亲,重儿子;
{de[u]=de[f]+1; fa[u]=f; siz[u]=1; //包括自己 可能是更进一步修改整棵子树的时候好做吧,现在不知道; for(int i=h[u];~i;i=ne[i]){int t=e[i];if(t==f)continue; dfs1(t,u);siz[u]+=siz[t];if(siz[son[u]]<siz[t])son[u]=t; //如果是叶子节点进不来这层,son【u】=0; }return ;
}
void dfs2(int u,int f) //求出链头,轻链的链头是自己,重链的链头是重链最上面的元素;
{ top[u]=f; //f是u的链头 if(!son[u])return ;//是叶子节点返回 dfs2结束条件,不加的话 dfs2(son[u],f)就过深,一般不加,因为dfs再for循环里面; dfs2(son[u],f); //重链的链头是f; for(int i=h[u];~i;i=ne[i]){int v=e[i];if(v==fa[u]||v==son[u])continue; //不可以写成v==f,因为轻链的链头是他自己; dfs2(v,v); //轻链的链头是他自己; }
}
int LCA(int x,int y)
{while(top[x]!=top[y])//当不在一条链上; {if(de[top[x]]<de[top[y]])swap(x,y);//链头较深的先上 ; x=fa[top[x]];//到到这条链的下一条链的链尾; }return de[x]<de[y]?x:y;
}
int main()
{memset(h,-1,sizeof h);//这句如果初始化idx=1&&只用建一个图,那么不用初始化h了; int n,m,s;scanf("%d%d%d",&n,&m,&s);for(int i=1,u,v;i<n;i++){scanf("%d%d",&u,&v);add(u,v);add(v,u);} dfs1(s,0);dfs2(s,s);while(m--){int a,b;scanf("%d%d",&a,&b);printf("%d\n",LCA(a,b));}return 0;
}
倍增
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N=5e5+10;
int fa[N][31],deep[N];
vector<int>v[N];
int n,m,s,a,b,c,ans=0;void dfs(int root,int fno)
{fa[root][0]=fno;deep[root]=deep[fno]+1;for(int i=1;i<31;i++)fa[root][i]=fa[fa[root][i-1]][i-1];int sz=v[root].size();for(int i=0;i<sz;i++){int t=v[root][i]; if(t==fno)continue;dfs(t,root);}
}
int lca(int x,int y)
{if(deep[x]>deep[y])swap(x,y);int sz=deep[y]-deep[x]; for(int i=0;sz;i++,sz>>=1)//先走到同一高度,那么再走相同的步数就到lca的前一个点; if(sz&1)y=fa[y][i];if(x==y)return x; //特判; for(int i=30;i>=0;i--) //为啥要走到零呢?。。难道是走到lca的前一个点;??? if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; //lca的前一个点的下一个点是lca(当是废话吧)
}int main()
{scanf("%d%d%d",&n,&m,&s);for(int i=1;i<=n;i++)v[i].clear();for(int i=1;i<n;i++){scanf("%d%d",&a,&b);v[a].push_back(b),v[b].push_back(a);}dfs(s,0);for(int i=0;i<m;i++){scanf("%d%d",&a,&b);printf("%d\n",lca(a,b));}return 0;
}
好像第二个代码好看。。