树,LCA,最近公共祖先,倍增
最近公共祖先,
树上倍增,LCA,
fa [ i ] [ j ] 表示 i 节点向上 2j 的祖先
很像dp,
k 属于 [ 1 , log ( n ) ] ,f [ x ][ k ] = f [ f [ x ] [ k-1 ]] [k-1]
算lca时,
先不妨设 d [ x ] >= d [ y ]
二进制拆分
尝试从x 向上走 k = 2log (n),~~,21,20,
检查到的点是否比 y 深
每次检查中,若是,x= f [ x ] [ k ]
若仍未相会, 即 f [ x ] [ k ] != f [ y ] [ k ]
令 x = f [ x ] [ k ], y = f [ y ] [ k ]
最后,若 x = y , lca ( x , y )=y
看看代码
#include <cstdio> #include <iostream> #include <string> #include <bits/stdc++.h> using namespace std; #define MAXN 50010 int fa[MAXN][20]; //f[i][j]表示i的2^j的祖先 int dep[MAXN];//深度 int dis[MAXN];//到根节点距离 struct edge { int v; int w; int nxt; } e[MAXN*2]; int head[MAXN]; int T,n,m,cnt; int t;//指数次幂 t=(log(n)/log(2))+1 void add(int x,int y,int z) { e[++cnt].v=y; e[cnt].w=z; e[cnt].nxt=head[x]; head[x]=cnt; } queue<int> q; void bfs() { //预处理 q.push(1); dep[1]=1; while (q.size()) { int x=q.front(); q.pop(); for (int i=head[x]; i; i=e[i].nxt) { int y=e[i].v; if (dep[y]) continue; dep[y]=dep[x]+1; dis[y]=dis[x]+e[i].w; fa[y][0]=x; for (int j=1; j<=t; j++) { fa[y][j]=fa[fa[y][j-1]][j-1]; } q.push(y); } } } int lca(int x,int y) { if (dep[x]>dep[y]) swap(x,y); for (int i=t; i>=0; i--) { if (dep[fa[y][i]]>=dep[x]) { y=fa[y][i]; } } if (x==y) return x; for (int i=t; i>=0; i--) { if (fa[x][i]!=fa[y][i]) { x=fa[x][i]; y=fa[y][i]; } } return fa[y][0]; } int main () { memset(head,0,sizeof(head)); memset(dep,0,sizeof(dep)); cnt=0; cin>>n>>m; t=(int)(log(n)/log(2))+1; //cout<<t<<endl; for (int i=1,x,y,z; i<n; i++) { cin>>x>>y>>z; add(x,y,z); add(y,x,z); } bfs();/* for (int i=1; i<=n; i++) { cout<<dep[i]<<" "; } cout<<endl; for (int i=1; i<=n; i++) { cout<<dis[i]<<" "; } cout<<endl;*/ for (int i=1,x,y,len; i<=m; i++) { //询问 cin>>x>>y; int k; k=lca(x,y); cout<<k<<endl; len=dis[x]+dis[y]-2*dis[k]; cout<<len<<endl; } return 0; } /* 10 5 1 2 2 1 3 4 2 4 3 2 5 7 3 6 2 3 7 4 4 8 2 5 9 3 6 10 1 6 7 9 3 8 5 10 6 4 7 */
还有一种:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,q,cnt; int deep[1001],head[1001],dis[1001],fa[1001][11]; bool vis[1001]; struct data{int to,next,v;}e[2001]; void ins(int u,int v,int w) {e[++cnt].to=v;e[cnt].next=head[u];e[cnt].v=w;head[u]=cnt;} void insert(int u,int v,int w) {ins(u,v,w);ins(v,u,w);} void dfs(int x) { vis[x]=1; for(int i=1;i<=9;i++) { if(deep[x]<(1<<i))break; fa[x][i]=fa[fa[x][i-1]][i-1]; } for(int i=head[x];i;i=e[i].next) { if(vis[e[i].to])continue; deep[e[i].to]=deep[x]+1; dis[e[i].to]=dis[x]+e[i].v; fa[e[i].to][0]=x; dfs(e[i].to); } } int lca(int x,int y) { if(deep[x]<deep[y])swap(x,y); int d=deep[x]-deep[y]; for(int i=0;i<=9;i++) if((1<<i)&d)x=fa[x][i]; for(int i=9;i>=0;i--) if(fa[x][i]!=fa[y][i]) {x=fa[x][i];y=fa[y][i];} if(x==y)return x; else return fa[x][0]; } int main() { scanf("%d%d",&n,&q); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); insert(u,v,w); } dfs(1); for(int i=1;i<=q;i++) { int x,y; scanf("%d%d",&x,&y); printf("%d\n",dis[x]+dis[y]-2*dis[lca(x,y)]); } return 0; }
OK啦