這個有兩種方法:數組
就是維護一個節點的第\(2^0,\ 2^1,\ 2^2\ ...\)層父親,這樣的話咱們在後面查詢的時候就能夠直接「跳」着找。spa
void pushup() { step=log(maxd*1.0)/log(2.0); for(int i=1;i<=step;i++) for(int p=1;p<=n;p++) if( fa[p][i-1] ) fa[p][i]=fa[ fa[p][i-1] ][i-1]; return; }
而後查詢的時候,先讓兩個點跳到同一深度。code
因此要讓較深的一個點先往上跳:class
if( dep[x]<dep[y] ) swap(x,y); for(int i=step;i>=0;i--) if( dep[x]-(1<<i)>=dep[y] ) x=fa[x][i];
第二行至關於將\(dep(x)-dep(y)\)的值作二進制拆分。二進制
跳到同一深度以後,若是兩個節點已經跳到同一個位置,就直接退出。方法
不然,就要繼續同時往上跳,可是,在跳的時候要保證:它們各自跳到的位置必須是不同的!否則的話它們可能都跳到了\(LCA\)的上面!查詢
整個功能段見下(省略了建圖部分):top
struct LCA { int fa[maxn][22],dep[maxn]; int maxd; void dfs(int x,int f,int d) { fa[x][0]=f,dep[x]=d; maxd=max( maxd,d ); for(int i=G.Head[x];i;i=G.Next[i]) { Graph::Edge e=G.edges[i]; if( e.to==f ) continue; dfs(e.to,x,d+1); } return; } int step; void pushup() { step=log(maxd*1.0)/log(2.0); for(int i=1;i<=step;i++) for(int p=1;p<=n;p++) if( fa[p][i-1] ) fa[p][i]=fa[ fa[p][i-1] ][i-1]; return; } int LCA(int x,int y) { if( dep[x]<dep[y] ) swap(x,y); for(int i=step;i>=0;i--) if( dep[x]-(1<<i)>=dep[y] ) x=fa[x][i]; if( x==y ) return y; for(int i=step;i>=0;i--) if( fa[x][i]!=fa[y][i] ) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } }SOL;
這個更簡單,用\(top\)數組直接跳就好了……co