在线倍增算法求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;
}
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;
}
相关文章推荐
- LCA三种算法学习(离线算法tarjan+在线算法转rmq+在线倍增)例题poj1330、1470;hdu4547、2874
- 求LCA最近公共祖先的在线倍增算法模板_C++
- 最近公共祖先(LCA)算法实现过程 【Tarjan离线+倍增在线+RMQ】
- poj1330 lca倍增算法模板
- LCA-倍增法(在线)O(nlogn)-O(logn)
- LCA在线算法学习笔记
- POJ 1330 Nearest Common Ancestors(在线倍增LCA)
- 倍增 - 强制在线的LCA
- 倍增(在线)求LCA
- POJ1470 倍增法在线求LCA
- HDU 6203 ping ping ping(在线倍增LCA+BIT)
- 多校第一场 1009 hdu 5296 Annoying problem(dfs序+在线倍增lca)
- LCA 在线倍增法 求最近公共祖先
- HDU 6110 路径交(线段树+在线倍增LCA)
- LCA-倍增法(在线)
- LCA(离线Tarjan算法,在线倍增法)详解
- LCA (最近公共祖先)倍增做法 —— O(nlogn)预处理 O(logn)(在线)查询
- Algorithm---LCA(倍增算法)
- 求LCA最近公共祖先的在线ST算法_C++
- 在线倍增法求LCA专题