D155 最近公共祖先 T72503 点的距离
D155 最近公共祖先 T72503 点的距离_哔哩哔哩_bilibili
给定一棵 n 个点的树,Q 个询问,每次询问点 x 到点 y 两点之间的距离。
思路
树上两点之间的距离,必然要经过它们的最近公共祖先 $lca$
周游一遍树,预处理出各点到根的距离 $d[i]$,各点的倍增祖先 $fa[i][j]$
每次询问 (x,y),可以 $d(x,y)=d[x]+d[y]-2*d[lca]$

相关板子:
// LCA 倍增算法 O(nlogn) #include<bits/stdc++.h> using namespace std; const int N=100010; int n,m; vector<int> e[N]; int dep[N],fa[N][19],d[N]; void dfs(int u,int f){ //预处理dep,fa,d数组 dep[u]=dep[f]+1; fa[u][0]=f; for(int i=1; i<=18; i++) fa[u][i]=fa[fa[u][i-1]][i-1]; for(int v:e[u]){ if(v==f) continue; d[v]=d[u]+1; //v到根的距离 dfs(v,u); } } int lca(int x,int y){ //求LCA if(dep[x]<dep[y]) swap(x,y); for(int i=18; i>=0; i--)if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if(x==y) return x; for(int i=18; i>=0; i--)if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int main(){ scanf("%d",&n); for(int i=1,a,b; i<n; i++){ scanf("%d%d",&a,&b); e[a].push_back(b); e[b].push_back(a); } dfs(1,0); scanf("%d",&m); for(int a,b;m--;){ scanf("%d%d",&a,&b); printf("%d\n",d[a]+d[b]-d[lca(a,b)]*2); } }
// 树链剖分 #include<bits/stdc++.h> using namespace std; const int N=100010; int n,m,a,b,c; vector<int> e[N]; int dep[N],fa[N],son[N],sz[N],dis[N]; int top[N]; void dfs1(int u,int father){ fa[u]=father,dep[u]=dep[father]+1,sz[u]=1; for(int v:e[u]){ if(v==father) continue; dis[v]=dis[u]+1; dfs1(v,u); sz[u]+=sz[v]; if(sz[son[u]]<sz[v])son[u]=v; } } void dfs2(int u,int t){ top[u]=t; if(!son[u]) return; dfs2(son[u],t); for(int v:e[u]){ if(v==fa[u]||v==son[u])continue; dfs2(v,v); } } int lca(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); x=fa[top[x]]; } return dep[x]<dep[y]?x:y; } int main(){ scanf("%d",&n); for(int i=1; i<n; i++){ scanf("%d%d",&a,&b); e[a].push_back(b); e[b].push_back(a); } dfs1(1,0); dfs2(1,1); scanf("%d",&m); while(m--){ scanf("%d%d",&a,&b); int d=dis[a]+dis[b]-dis[lca(a,b)]*2; printf("%d\n",d); } }
// Tarjan 算法 #include<bits/stdc++.h> using namespace std; typedef pair<int,int> PII; const int N=100010,M=N*2; int n,m,a,b; vector<int> e[N]; vector<PII> query[N]; int fa[N],vis[N],dis[N]; int ans[M]; int find(int u){ if(fa[u]==u) return u; return fa[u]=find(fa[u]); } void tarjan(int u){ vis[u]=1; for(int v:e[u]){ if(vis[v]) continue; dis[v]=dis[u]+1; tarjan(v); fa[v]=u; } for(auto ed:query[u]){ int v=ed.first,i=ed.second; if(vis[v]) ans[i]=dis[u]+dis[v]-dis[find(v)]*2; } } int main(){ scanf("%d",&n); for(int i=1; i<n; i++){ scanf("%d%d",&a,&b); e[a].push_back(b); e[b].push_back(a); } scanf("%d",&m); for(int i=1; i<=m; i++){ scanf("%d%d",&a,&b); query[a].push_back({b,i}); query[b].push_back({a,i}); } for(int i=1;i<=n;i++) fa[i]=i; tarjan(1); for(int i=1; i<=m; i++) printf("%d\n",ans[i]); }
浙公网安备 33010602011771号