树上倍增法求LCA
输入
第一行是单个整数T(T <= 10),表示测试数据的数量。
对于每个测试数据,在第一行中有两个数字n(2 <= n <= 40000)和m
对于每个测试数据,在第一行中有两个数字n(2 <= n <= 40000)和m
(1 <= m <= 200),结点数量和查询数量。下面的n-1行每个包含三个数
字i,j,k,分隔在一个空格中,这意味着有一条连接结点i和结点j的道路,
长度为k(0 <k <= 40000)。结点是标记为1到n。接下来m行每个都有
不同的整数i和j,你要回答结点i和结点j之间的距离。
输出
对于每个测试用例,输出m行。每行代表查询的答案。在每个测试用例后
输出一条平淡的线。
样例输入
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
样例输出
10
25
100
100
解析:这是一个LCA模板,求x,y的LCA后计算x,y至LCA(x,y)的距离和,直接写代码(有注释)
#include<bits/stdc++.h> using namespace std; struct Edge//结构体求路径 { int to,next,val; }e[40005]; int head[40005]; int tot=1; int f[40005][50]; int g[40005][50]; int d[40005]; int n,m; inline int read()//read快读 { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline int Log(int x)//求一个数的log { int i=1; while(1<<i<x) { i++; } return i; } inline void add(int u,int v,int w)//将一个路径加上 { e[tot].to=v; e[tot].val=w; e[tot].next=head[u]; head[u]=tot++; } inline void dfs(int idx,int fa_)//dfs预处理父亲以及到父亲的距离 { for(int i=head[idx];i;i=e[i].next) { if(e[i].to!=fa_) { f[e[i].to][0]=idx; g[e[i].to][0]=e[i].val; dfs(e[i].to,idx); } } } int SS_BZ(int x,int y)//树上倍增函数 { int sum=0; if(d[x]<d[y]) //如果x的深度小于y,就先交换x,y,然后将x向上找父亲,直到深度y相同 { swap(x,y); int sum4=0; sum4+=d[x]-d[y]; int sum2=sum4; int sum3=0; while(sum2) { if(sum2%2) { sum+=g[x][sum3]; x=f[x][sum3]; } sum3++; sum2/=2; } } else if(d[x]>d[y]) //如果x的深度大于y,就先直接将x向上找父亲,直到深度y相同 { int sum4=0; sum4+=d[x]-d[y]; int sum2=sum4; int sum3=0; while(sum2) { if(sum2%2) { sum+=g[x][sum3]; x=f[x][sum3]; } sum3++; sum2/=2; } } while(1) { int i=0; while(f[x][i]!=f[y][i])//如果x的2^i辈祖先= y的2^i辈祖先,则x,y 的LCA的深度>x,y的2^i辈祖先 { i++; } i--; if(i<=0)//如果i的值<=0,则结束 { sum+=(g[x][0]+g[y][0]); break; } sum+=(g[x][i]+g[y][i]); x=f[x][i],y=f[y][i]; } return sum;//将x-->LCA(x,y)+LCA(x,y)-->y的值返回 } int main() { int T; scanf("%d",&T); while(T--)//T组数据 { //初始化 tot=1; memset(d,0,sizeof(d)); memset(f,0,sizeof(f)); memset(e,0,sizeof(e)); memset(head,0,sizeof(head)); memset(g,0,sizeof(g)); n=read(),m=read(); int LOG=Log(n); //读入边 for(int i=1;i<=n-1;i++) { int x,y,z; x=read(),y=read(),z=read(); add(x,y,z); add(y,x,z); } //预处理 dfs(1,0); for(int i=1;i<=n;i++) f[1][i]=0; for(int i=2;i<=n;i++) { for(int j=1;j<=LOG;j++) { f[i][j]=f[f[i][j-1]][j-1]; } } for(int i=1;i<=n;i++) g[1][i]=0; for(int i=2;i<=n;i++) { for(int j=1;j<=LOG;j++) { g[i][j]=g[f[i][j-1]][j-1]+g[i][j-1]; } } for(int i=1;i<=n;i++) d[i]=d[f[i][0]]+1; //找x,y的距离并输出 for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); int p=SS_BZ(x,y); printf("%d",p); } } return 0; } /* 2 3 2 1 2 10 3 1 15 1 2 2 3 2 2 1 2 100 1 2 2 1 */