3055: Nearest Common Ancestors
Time Limit: 1 Sec Memory Limit: 128 MBDescription
给定N个节点的一棵树,有K次查询,每次查询a和b的最近公共祖先。
样例中的16和7的公共祖先(LCA:Least Common Ancestors)是4。
Input
第一行两个整数N(1 < N <= 105)、K(1 <= K <= 105)
第2~N行,每行两个整数a、b(1 <= a,b <= N),表示a是b的父亲。
第N+1~N+K+1行,每行两个整数a、b(1 <= a,b <= N),表示询问a和b的最近公共祖先是谁。
Output
输出K行,第i行表示第i个查询的最近公共祖先是谁。
Sample Input
16 11 148 510 165 94 68 44 101 136 1510 116 710 216 38 116 1216 7
Sample Output
4
HINT
30%数据 N<=20,K<=5。小数据,方便调试
50%数据 N<=1000,K<=1000。中数据,暴力可过
100%数据 1 < N <= 105,1 <= K <= 105。大数据,请使用树上倍增、LCA转RMQ&ST、离线Tarjan、树链剖分求LCA
Source
poj1330改
#include<stdio.h>
int n,t;
int f[100001][21];
/*‘f[i][j]从第i个点向上蹦2^j步的落脚点’*/
int log_me[100001];
int head[100001];
int to[100001];
int next[100001];
int level[100001];
int queue[100001];
int power[21];
int idx,all_fa,max_dep;
bool is[100001];
void bfs(int p)
{
int front,tail;
front=tail=0;
queue[tail++]=p;
while(front<tail)
{
int idx2=queue[front++];
for(int i=head[idx2];i;i=next[i])
{
level[to[i]]=level[idx2]+1;
queue[tail++]=to[i];
if(level[to[i]]>max_dep)
max_dep=level[to[i]];
}
}
}
int main()
{
scanf("%d%d",&n,&t);
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
f[b][0]=a;
next[++idx]=head[a];
head[a]=idx;
to[idx]=b;
is[b]=true;
}
log_me[0]=-1;
for(int i=1;i<=n;i++)
{
log_me[i]=log_me[i>>1]+1;
if(!is[i])
all_fa=i;
}
power[0]=1;
for(int i=1;i<=17;i++)
power[i]=power[i-1]*2;
bfs(all_fa);
f[all_fa][0]=all_fa;
f[0][0]=all_fa;
for(int j=1;j<=17;j++)
for(int i=0;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
for(;t;t--)
{
int a,b;
scanf("%d%d",&a,&b);
if(a==b)
{
printf("%d\n",a);
continue;
}
int deep,low,diff_val;
if(level[a]>level[b])
deep=a,low=b;
else
deep=b,low=a;
diff_val=level[deep]-level[low];
for(;level[deep]>level[low];diff_val=level[deep]-level[low])
deep=f[deep][log_me[diff_val]];
if(deep==low)
{
printf("%d\n",deep);
continue;
}
int dep=log_me[level[deep]];
while(dep>=0)
{
if(f[deep][dep]!=f[low][dep])
{
deep=f[deep][dep];
low=f[low][dep];
dep=log_me[level[deep]];
}
dep--;
}
printf("%d\n",f[deep][0]);
}
}