您的位置:首页 > 其它

在线倍增算法求LCA

2017-06-20 16:04 351 查看
给定一棵树,询问两个节点的中点。

A[x,i]代表与x深度相差2的i次方的祖先。A满足性质

A[x,i+1]=A[A[x,i],i]

令j是使2的j次方小于等于H的最大非负整数

Ancestor(x,H)=Ancestor(A[x,j],H-2的j次方)

则LCA(x,y)=LCA(Ancestor(x,deep(y)-deep(x)),y)

#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
#include<vector>
using namespace std;

vector<int>g[10001];

int A[10001][15];
int d[10001];

void dfs(int root,int deep,int p)
{
d[root]=deep;
A[root][0]=p;
for(int i=1;i<15;i++)
{
A[root][i]=A[A[root][i-1]][i-1];
}
for(int i=0;i<g[root].size();i++)
{
if(!d[g[root][i]])

dfs(g[root][i],deep+1,root);
}
}

void BuildTree(int N)
{
int a,b;
memset(A,0,sizeof(A));
memset(d,0,sizeof(d));
for(int i=1;i<=N;i++)g[i].clear();
for(int i=1;i<N;i++)
{
scanf("%d%d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
dfs(1,1,0);
}

int Ancestor(int x,int len)
{
for(int i=14;i>=0;i--)
{
if(len >= 1<<i)
{
len -= 1<<i;
x=A[x][i];
}
}
return x;
}

int LCA(int x,int y)
{
if(d[x]>d[y])
{
x=Ancestor(x,d[x]-d[y]);
}
else
y=Ancestor(y,d[y]-d[x]);
if(x==y)
return x;
int ret;
int i=14;
while(i--)
{
if(A[x][i]==A[y][i])
{
ret=A[x][i];
}
else
{
x=A[x][i];
y=A[y][i];
}
}
return ret;
}

void Answer(int x,int y)
{
int p=LCA(x,y);
int lenx=d[x]-d[p],leny=d[y]-d[p];
int midlen=(lenx+leny)/2;
int nx,ny;
if(lenx>leny)
{
nx=Ancestor(x,midlen);
if((lenx+leny)%2==0)
{
printf("%d\n",nx);
}
else
{
ny=A[nx][0];
printf("%d %d\n",nx,ny);
}
}
else
{
ny=Ancestor(y,midlen);
if((lenx+leny)%2==0)
{
printf("%d\n",ny);
}
else
{
nx=A[ny][0];
printf("%d %d\n",nx,ny);
}
}
}

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int N;
scanf("%d",&N);
BuildTree(N);
int M;
scanf("%d",&M);
while(M--)
{
int x,y;
scanf("%d%d",&x,&y);
Answer(x,y);
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: