洛谷 P3379 【模板】最近公共祖先(LCA) (在线倍增+离线Tarjan)

2023-10-05 23:31

本文主要是介绍洛谷 P3379 【模板】最近公共祖先(LCA) (在线倍增+离线Tarjan),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式:

输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

输入样例#1:

5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5

输出样例#1:

4
4
1
4
4

思路

题如其名,就是lca的模板。我就存一存我的lca模板~

离线Tarjan

#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
#define inf 1000000
#define mem(a,b) memset(a,b,sizeof(a))
const int N=500000+7;
int pre[N],first[N],first2[N],tot,tot2;
bool vis[N];//标记有没有询问
int n;
struct edge
{int v,next;
} e[2*N];
struct Query
{int v,w,next;
} query[2*N];void add_edge(int u,int v)
{e[tot].v=v;e[tot].next=first[u];first[u]=tot++;
}void add_query(int u,int v)
{query[tot2].v=v;query[tot2].w=-1;query[tot2].next=first2[u];first2[u]=tot2++;
}int find(int x)
{return x==pre[x]?x:pre[x]=find(pre[x]);
}int lca(int u,int fa)
{for(int i=first[u]; ~i; i=e[i].next){int v=e[i].v;if(v==fa) continue;lca(v,u);pre[v]=u;}vis[u]=1;for(int i=first2[u]; ~i; i=query[i].next){int v=query[i].v;if(vis[v])query[i].w=find(v);}
}void init()
{mem(first,-1);mem(first2,-1);mem(vis,0);tot=0;tot2=0;for(int i=1; i<=n; i++)pre[i]=i;
}int main()
{int m,s,u,v;scanf("%d%d%d",&n,&m,&s);init();for(int i=1; i<n; i++){scanf("%d%d",&u,&v);add_edge(u,v);add_edge(v,u);}for(int i=1; i<=m; i++){scanf("%d%d",&u,&v);add_query(u,v);add_query(v,u);}lca(s,pre[s]);for(int i=0; i<tot2; i++)if(query[i].w!=-1)printf("%d\n",query[i].w);return 0;
}

在线倍增

#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
#define inf 1000000
#define mem(a,b) memset(a,b,sizeof(a))
const int N=500000+7;int n,m,s;
int tot;
int first[N],d[N],p[N][21];struct edge
{int v,next;
} e[2*N];void add_edge(int u,int v)
{e[tot].v=v;e[tot].next=first[u];first[u]=tot++;
}void dfs(int u,int fa)
{d[u]=d[fa]+1;p[u][0]=fa;for(int i=1; (1<<i)<=d[u]; i++)p[u][i]=p[p[u][i-1]][i-1];for(int i=first[u]; ~i; i=e[i].next){int v=e[i].v;if(v!=fa)dfs(v,u);}
}int lca(int a,int b)
{if(d[a]>d[b]) swap(a,b);//保证a在b点的上方for(int i=20; i>=0; i--)if(d[a]<=d[b]-(1<<i))b=p[b][i];  //把b移到和a同一个深度if(a==b) return a;for(int i=20; i>=0; i--){if(p[a][i]==p[b][i])continue;elsea=p[a][i],b=p[b][i];//一起向上跳跃}return p[a][0];
}void init()
{tot=0;mem(first,-1);mem(d,0);mem(p,0);
}
int main()
{init();int a,b;scanf("%d%d%d",&n,&m,&s);for(int i=1; i<n; i++){scanf("%d%d",&a,&b);add_edge(a,b);add_edge(b,a);}dfs(s,0);for(int i=1; i<=m; i++){scanf("%d%d",&a,&b);printf("%d\n",lca(a,b));}return 0;
}

这篇关于洛谷 P3379 【模板】最近公共祖先(LCA) (在线倍增+离线Tarjan)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/152284

相关文章

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

电力系统中的A类在线监测装置—APView400

随着电力系统的日益复杂和人们对电能质量要求的提高,电能质量在线监测装置在电力系统中得到广泛应用。目前,市场上的在线监测装置主要分为A类和B类两种类型,A类和B类在线监测装置主要区别在于应用场景、技术参数、通讯协议和扩展性。选择时应根据实际需求和应用场景综合考虑,并定期维护和校准。电能质量在线监测装置是用于实时监测电力系统中的电能质量参数的设备。 APView400电能质量A类在线监测装置以其多核

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

poj1330(LCA最近公共祖先)

题意:求最近公共祖先 思路:之前学习了树链剖分,然后我就用树链剖分的一小部分知识就可以解这个题目了,记录每个结点的fa和depth。然后查找时,每次将depth大的结点往上走直到x = y。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstring>

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

最大流、 最小费用最大流终极版模板

最大流  const int inf = 1000000000 ;const int maxn = 20000 , maxm = 500000 ;struct Edge{int v , f ,next ;Edge(){}Edge(int _v , int _f , int _next):v(_v) ,f(_f),next(_next){}};int sourse , mee