LCA——JD 3055 Nearest Common Ancestors

本文介绍了一个涉及树结构的问题——寻找两个节点的最近公共祖先。通过给出的代码示例,展示了如何利用树上倍增等算法解决该问题,并针对不同规模的数据提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3055: Nearest Common Ancestors

Time Limit: 1 Sec   Memory Limit: 128 MB

Description

给定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改

  1. #include<stdio.h>  
  2. int n,t;  
  3. int f[100001][21];  
  4. /*‘f[i][j]从第i个点向上蹦2^j步的落脚点’*/  
  5. int log_me[100001];  
  6. int head[100001];  
  7. int to[100001];  
  8. int next[100001];  
  9. int level[100001];  
  10. int queue[100001];  
  11. int power[21];  
  12. int idx,all_fa,max_dep;  
  13. bool is[100001];  
  14. void bfs(int p)  
  15. {  
  16.     int front,tail;  
  17.     front=tail=0;  
  18.     queue[tail++]=p;  
  19.     while(front<tail)  
  20.     {  
  21.         int idx2=queue[front++];  
  22.         for(int i=head[idx2];i;i=next[i])  
  23.         {  
  24.             level[to[i]]=level[idx2]+1;  
  25.             queue[tail++]=to[i];  
  26.             if(level[to[i]]>max_dep)  
  27.                 max_dep=level[to[i]];  
  28.         }  
  29.     }  
  30. }  
  31. int main()  
  32. {  
  33.     scanf("%d%d",&n,&t);  
  34.     for(int i=1;i<n;i++)  
  35.     {  
  36.         int a,b;  
  37.         scanf("%d%d",&a,&b);  
  38.         f[b][0]=a;  
  39.         next[++idx]=head[a];  
  40.         head[a]=idx;  
  41.         to[idx]=b;  
  42.         is[b]=true;  
  43.     }  
  44.     log_me[0]=-1;  
  45.     for(int i=1;i<=n;i++)  
  46.     {  
  47.         log_me[i]=log_me[i>>1]+1;  
  48.         if(!is[i])  
  49.             all_fa=i;  
  50.     }  
  51.     power[0]=1;  
  52.     for(int i=1;i<=17;i++)  
  53.         power[i]=power[i-1]*2;  
  54.     bfs(all_fa);  
  55.     f[all_fa][0]=all_fa;  
  56.     f[0][0]=all_fa;  
  57.     for(int j=1;j<=17;j++)  
  58.         for(int i=0;i<=n;i++)  
  59.             f[i][j]=f[f[i][j-1]][j-1];  
  60.     for(;t;t--)  
  61.     {  
  62.         int a,b;  
  63.         scanf("%d%d",&a,&b);  
  64.         if(a==b)  
  65.         {  
  66.             printf("%d\n",a);  
  67.             continue;  
  68.         }  
  69.         int deep,low,diff_val;  
  70.         if(level[a]>level[b])  
  71.             deep=a,low=b;  
  72.         else  
  73.             deep=b,low=a;  
  74.         diff_val=level[deep]-level[low];  
  75.         for(;level[deep]>level[low];diff_val=level[deep]-level[low])  
  76.             deep=f[deep][log_me[diff_val]];  
  77.         if(deep==low)  
  78.         {  
  79.             printf("%d\n",deep);  
  80.             continue;  
  81.         }  
  82.         int dep=log_me[level[deep]];  
  83.         while(dep>=0)  
  84.         {  
  85.             if(f[deep][dep]!=f[low][dep])  
  86.             {  
  87.                 deep=f[deep][dep];  
  88.                 low=f[low][dep];  
  89.                 dep=log_me[level[deep]];  
  90.             }  
  91.             dep--;  
  92.         }  
  93.         printf("%d\n",f[deep][0]);  
  94.     }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值