树上倍增求LCA

大概思想就是,节点$i$的第$2^{j}$个父节点是他第$2^{j-1}$个父亲的第$2^{j-1}$个父亲

然后可以$O(nlogn)$时间内解决……

没了?

 1 //fa[i][j]表示i的第2^j个父节点
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 using namespace std;
 7 struct edge{
 8     int v,next;
 9 }a[100001];
10 int n,q,u,v,rt,tot=0,head[100001],fa[100001][31],dep[100001];
11 bool vis[100001];
12 void add(int u,int v){
13     a[++tot].v=v;
14     a[tot].next=head[u];
15     head[u]=tot;
16 }
17 void cal_dep(int u){
18     vis[u]=true;
19     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
20         int v=a[tmp].v;
21         if(!vis[v]){
22             dep[v]=dep[u]+1;
23             cal_dep(v);
24         }
25     }
26 }
27 void cal(){
28     for(int j=1;j<=30;j++){
29         for(int i=1;i<=n;i++){
30             fa[i][j]=fa[fa[i][j-1]][j-1];
31         }
32     }
33 }
34 int lca(int x,int y){
35     if(dep[x]<dep[y]){
36         swap(x,y);
37     }
38     int s=dep[x]-dep[y];
39     for(int i=0;i<30;i++){
40         if((1<<i)&s)x=fa[x][i];
41     }
42     if(x==y)return x;
43     for(int i=29;i>=0;i--){
44         if(fa[x][i]!=fa[y][i]){
45             x=fa[x][i];
46             y=fa[y][i];
47         }
48     }
49     return fa[x][0];
50 }
51 int main(){
52     memset(head,-1,sizeof(head));
53     memset(fa,0,sizeof(fa));
54     memset(dep,0,sizeof(dep));
55     memset(vis,0,sizeof(vis));
56     scanf("%d%d",&n,&q);
57     for(int i=1;i<n;i++){
58         scanf("%d%d",&u,&v);
59         add(u,v);
60         fa[v][0]=u;
61         //if(!fa[u][0])rt=u;
62     }
63     dep[1]=1;
64     cal_dep(1);
65     cal();
66     for(int i=1;i<=q;i++){
67         scanf("%d%d",&u,&v);
68         printf("%d\n",lca(u,v));
69     }
70     return 0;
71 }
72 /*
73 16 4
74 1 2
75 1 3
76 2 4
77 2 5
78 2 6
79 3 7
80 4 8
81 4 9
82 5 10
83 7 11
84 7 12
85 10 13
86 10 14
87 10 15
88 12 16
89 4 7
90 9 16
91 11 16
92 15 8
93 ------
94 1
95 1
96 7
97 2
98 */

原文地址:https://www.cnblogs.com/dcdcbigbig/p/8952821.html

时间: 2024-10-22 21:55:15

树上倍增求LCA的相关文章

[luogu3379]最近公共祖先(树上倍增求LCA)

题意:求最近公共祖先. 解题关键:三种方法,1.st表 2.倍增法 3.tarjan 此次使用倍增模板 #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll; int n,m,root,cnt

CF 519E(树上倍增求lca)

传送门:A and B and Lecture Rooms 题意:给定一棵树,每次询问到达点u,v距离相等的点有多少个. 分析:按情况考虑: 1.abs(deep[u]-deep[v])%2==1时,必定不存在到达u,v距离相等的点. 2.如果deep[u]==deep[v]时,ans=n-num[lca(u,v)u在的儿子树]-num[lca(u,v)v在的儿子树]. 3.如果deep[u]!=deep[v]时,在u到v的路径中找出到达u,v相等的节点x,则ans=num[x]-num[u在的

HDU 4081 Qin Shi Huang&#39;s National Road System 最小生成树+倍增求LCA

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4081 Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5428    Accepted Submission(s): 1902 Problem Description

【LCA】倍增求LCA

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 复制 5 5 4 3 1 2 4

hdu 2586 How far away ? 倍增求LCA

倍增求LCA LCA函数返回(u,v)两点的最近公共祖先 #include <bits/stdc++.h> using namespace std; const int N = 40010*2; struct node { int v,val,next; node(){} node(int vv,int va,int nn):v(vv),val(va),next(nn){} }E[N]; int n,m; int tot,head[N],dis[N],f[N][20],dep[N]; void

POJ 1986:Distance Queries(倍增求LCA)

http://poj.org/problem?id=1986 题意:给出一棵n个点m条边的树,还有q个询问,求树上两点的距离. 思路:这次学了一下倍增算法求LCA.模板. dp[i][j]代表第i个点的第2^j个祖先是哪个点,dp[i][0] = i的第一个祖先 = fa[i].转移方程:dp[i][j] = dp[dp[i][j-1][j-1]. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm&g

tarjan,树剖,倍增求lca

1.tarjan求lca Tarjan(u)//marge和find为并查集合并函数和查找函数 { for each(u,v) //访问所有u子节点v { Tarjan(v); //继续往下遍历 marge(u,v); //合并v到u上 标记v被访问过; } for each(u,e) //访问所有和u有询问关系的e { 如果e被访问过; u,e的最近公共祖先为find(e); } } 2.倍增lca(在线) #include<bits/stdc++.h> using namespace st

【OI】倍增求LCA

╭(′▽`)╯ 总之,我们都知道lca是啥,不需要任何基础也能想出来怎么用最暴力的方法求LCA,也就是深度深的点先跳到深度浅的点的同一深度,然后一起向上一步步跳.这样显然太慢了! 所以我们要用倍增,倍增比较屌,直接2^k速度往上跳,而且复杂度和树剖lca差不多,那么步骤分为两步 1.让两个点到同一深度 2.到了同一深度同步往上跳 反正我一开始看的时候一直在想,万一跳过了怎么办?哈哈哈,所以说我们有办法嘛: 定义deepv为v点的深度,设两个要求lca的点分别为a,b,且deepa >= deep

(贪心+倍增求LCA) hdu 4912

Paths on the tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1097    Accepted Submission(s): 366 Problem Description bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n. T