树上倍增法求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
*/

浙公网安备 33010602011771号