P3379 【模板】最近公共祖先(LCA)(倍增LCA)

题目链接:https://www.luogu.org/problem/P3379

题目大意:

  给一棵以s为根的无向树,回答m个询问,回答出a和b最近的公共祖先。

解题报告:

  倍增LCA的模板题,用一个数组 f [i] [j]表示i结点的第$2^{j}$个祖先。显然,一个点的祖先是f[i][0],对于当前点的第$2^{j}$个祖先的第$2^{j}$个祖先,等于当前点的第$2^{j+1}$个祖先,因为$2^{j}+2^{j}=2^{j+1}$。所以有递推式$f[i][j]=f[f[i][j-1]][j-1]$

  还有一个常数优化是打表预处理出log2(i)+1的值。

AC代码:

 1 #include<vector>
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<cmath>
 5 #include<queue>
 6 #include<stack>
 7 #include<cmath>
 8 #include<algorithm>
 9 #define numm ch-48
10 #define pd putchar(‘ ‘)
11 #define pn putchar(‘\n‘)
12 #define pb push_back
13 #define fi first
14 #define se second
15 #define fre1 freopen("1.txt","r",stdin)
16 #define fre2 freopen("2.txt","w",stdout)
17 using namespace std;
18 template <typename T>
19 void read(T &res) {
20     bool flag=false;char ch;
21     while(!isdigit(ch=getchar())) (ch==‘-‘)&&(flag=true);
22     for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
23     flag&&(res=-res);
24 }
25 template <typename T>
26 void write(T x) {
27     if(x<0) putchar(‘-‘),x=-x;
28     if(x>9) write(x/10);
29     putchar(x%10+‘0‘);
30 }
31 const int maxn=500010;
32 const int N=60;
33 const int inf=0x3f3f3f3f;
34 const int INF=0x7fffffff;
35 typedef long long ll;
36 struct node{
37     int v,net;
38 }e[maxn<<1];
39 int head[maxn],depth[maxn],lg[maxn],f[maxn][50],cnt;
40 void add(int u,int v) {
41     e[++cnt].v=v;
42     e[cnt].net=head[u];
43     head[u]=cnt;
44 }
45 void dfs(int fath,int now) {
46     depth[now]=depth[fath]+1;
47     f[now][0]=fath;
48     for(int i=1;(1<<i)<=depth[now];i++)
49         f[now][i]=f[f[now][i-1]][i-1];
50     for(int i=head[now];i!=-1;i=e[i].net)
51         if(e[i].v!=fath) dfs(now,e[i].v);
52 }
53 int lca(int x,int y) {
54     if(depth[x]<depth[y]) swap(x,y);
55     while(depth[x]>depth[y]) x=f[x][lg[depth[x]-depth[y]]-1];///x往父节点开始延伸
56     if(x==y) return x;  ///说明公共祖先为y,也就是当前的x
57     for(int i=lg[depth[x]]-1;~i;i--)
58         if(f[x][i]!=f[y][i])
59             x=f[x][i],y=f[y][i];
60     return f[x][0];
61 }
62 int main()
63 {
64     int n,m,s,a,b;
65     read(n),read(m),read(s);
66     fill(head+1,head+n+1,-1);
67     for(int i=1;i<=n-1;i++) {
68         read(a),read(b);
69         add(a,b),add(b,a);
70     }
71     dfs(s,s);
72     for(int i=1;i<=n;i++)   ///常数优化,预处理求出log2[i]+1的值
73         lg[i]=lg[i-1]+(1<<lg[i-1]==i);
74     for(int i=1;i<=m;i++) {
75         read(a),read(b);
76         write(lca(a,b));pn;
77     }
78     return 0;
79 }

代码在这里!

 

原文地址:https://www.cnblogs.com/wuliking/p/11269253.html

时间: 2024-10-04 17:59:04

P3379 【模板】最近公共祖先(LCA)(倍增LCA)的相关文章

最近公共祖先问题(LCA)模板

最近公共祖先问题(LCA)是求一颗树上的某两点距离他们最近的公共祖先节点,由于树的特性,树上两点之间路径是唯一的,所以对于很多处理关于树的路径问题的时候为了得知树两点的间的路径,LCA是几乎最有效的解法. 首先是LCA的倍增算法.算法主体是依靠首先对整个树的预处理DFS,用来预处理出每个点的直接父节点,同时可以处理出每个点的深度和与根节点的距离,然后利用类似RMQ的思想处理出每个点的 2 的幂次的祖先节点,这就可以用 nlogn 的时间完成整个预处理的工作.然后每一次求两个点的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

HDU 2586 How far away ?(LCA模板 近期公共祖先啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house

HDU 2586 How far away ?(LCA模板 最近公共祖先啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house

hihoCoder #1067 : 最近公共祖先&#183;二 [ 离线LCA tarjan ]

传送门: #1067 : 最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中辈分最低的一个是谁.远在美国的他们利用了一些奇妙的技术获得了国内许多人的相关信息,并且搭建了一个小小的网站来应付来自四面八方的请求. 但正如我们所能想象到的……这样一个简单的算法并不能支撑住非常大的访问量,所以摆在小Hi和小Ho面前的无非两种选择: 其一是

[模板]最近公共祖先LCA

本人水平有限,题解不到为处,请多多谅解 本蒟蒻谢谢大家观看 题目:传送门 倍增求LCA模板 code: #include<bits/stdc++.h> #pragma GCC optimize(3) using namespace std; int n,q,a,b,tot,m; int nxt[1000010],head[1000010],ver[1000010],dep[1000010],f[1000010][21]; //设f[x,k]表示x的2^k辈祖先,即从x向根节点走2^k步到达的节

树链剖分 [模板]最近公共祖先LCA

本人水平有限,题解不到为处,请多多谅解 本蒟蒻谢谢大家观看 题目:传送门 树链剖分:跑两遍dfs,第一遍找重边,第二遍找重链. 重儿子:父亲节点的所有儿子中子树结点数目最多(size最大)的结点: 轻儿子:父亲节点中除了重儿子以外的儿子: 重边:父亲结点和重儿子连成的边: 轻边:父亲节点和轻儿子连成的边: 重链:由多条重边连接而成的路径: 轻链:由多条轻边连接而成的路径 son[]表示重儿子,top[]表示重链所在的第一个节点,sz[]表示子节点数,fa[]表示父亲节点 图示: code: #i

树,LCA,最近公共祖先,倍增

最近公共祖先, 树上倍增,LCA, fa [ i ] [ j ] 表示 i 节点向上 2j 的祖先 很像dp, k 属于 [ 1 , log ( n ) ] ,f [ x ][ k ] = f [ f [ x ] [ k-1 ]] [k-1] 算lca时, 先不妨设 d [ x ] >= d [ y ] 二进制拆分 尝试从x 向上走 k = 2log (n),~~,21,20, 检查到的点是否比 y 深 每次检查中,若是,x= f [ x ] [ k ] 若仍未相会, 即 f [ x ] [ k

【算法】树上公共祖先的Tarjan算法

最近公共祖先问题 树上两点的最近公共祖先问题(LCA - Least Common Ancestors) 对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u和v的祖先且x的深度尽可能大.在这里,一个节点也可以是它自己的祖先. 例如,如图,在以A为根的树上 节点 8 和 9 的LCA为 4 节点 8 和 5 的LCA为 2 节点 8 和 3 的LCA为 1 在线算法与离线算法 区别就在于是同时处理询问后输出还是边询问边输出 在线算法是读入一组询问,查询一次后紧

【原创】洛谷 LUOGU P3379 【模板】最近公共祖先(LCA) -&gt; 倍增

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