您的位置:首页 > 其它

最近公共祖先(LCA)---倍增法

2017-01-12 22:03 387 查看
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define Size 1000000
using namespace std;
int be[Size],ne[Size],to[Size],e;
void add(int x,int y){to[++e]=y;ne[e]=be[x];be[x]=e;}
int deep[Size];
int fa[Size>>1][20];
bool vis[Size];
int read(){
int x=0;
char ch=getchar();
while(ch<'0' || ch>'9')ch=getchar();
while(ch>='0' && ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
void dfs(int x){
vis[x]=1;
for(int i=be[x];i;i=ne[i]){
if(!vis[to[i]]){
fa[to[i]][0]=x;//标记上一个为父亲节点
deep[to[i]]=deep[x]+1;
dfs(to[i]);
}
}
}
void build(int n){
int k=log(n)/log(2);
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)
if(fa[j][i-1]!=0 && fa[fa[j][i-1]][i-1]!=0)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
int query(int x,int y){
if(deep[x]<deep[y])swap(x,y);//把x作为深度较大的点
int t;
for(t=0;(1<<t)<=deep[x];t++);
t--;
for(int j=t;j>=0;j--)
if(deep[x]-(1<<j)>=deep[y])
x=fa[x][j];
if(x==y)return x;
for(int j=t;j>=0;j--){
if(fa[x][j]!=0 && fa[x][j]!=fa[y][j]){//不能为同一个点
x=fa[x][j];
y=fa[y][j];
}
}
return fa[x][0];
}
int main(){
int n,m,s;//n个点,m个边,以s点为根节点
n=read();m=read();s=read();
for(int i=1;i<n;i++){
int x,y;
x=read();y=read();
add(x,y);add(y,x);
}
deep[s]=1;
dfs(s);
build(n);
for(int i=1;i<=m;i++){
int x,y;
x=read();y=read();
printf("%d\n",query(x,y));
}
return 0;
}
/*
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5

4
4
1
4
4
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: