LCA求解的四种模板

LCA求解的四种模板

或许更好的阅读体验

树剖在线求解LCA

思想

树剖这里就不多解释了,求解LCA的过程就是轻重链的跳转,跟树剖求任意两点间的距离一样的操作,只不过不用线段树去维护disdisdis了,那就直接上代码吧。

代码

#include <bits/stdc++.h>using namespace std;typedef long long ll;
const int N = 1e6 + 10;int head[N], to[N << 1], nex[N << 1], cnt = 1;
int sz[N], dep[N], fa[N], son[N], top[N];
int n, m;inline int read() {int f = 1, x = 0;char c = getchar();while(c > '9' || c < '0') {if(c == '-')    f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x;
}void add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++;
}void dfs1(int rt, int f) {dep[rt] = dep[f] + 1;sz[rt] = 1, fa[rt] = f;for(int i = head[rt]; i; i = nex[i]) {if(to[i] == f)  continue;dfs1(to[i], rt);if(!son[rt] || sz[to[i]] > sz[son[rt]])son[rt] = to[i];sz[rt] += sz[to[i]];}
}void dfs2(int rt, int t) {top[rt] = t;if(!son[rt])    return ;dfs2(son[rt], t);for(int i = head[rt]; i; i = nex[i]) {if(to[i] == fa[rt] || to[i] == son[rt]) continue;dfs2(to[i], to[i]);}
}int solve(int x, int y) {while(top[x] != top[y]) {if(dep[top[x]] < dep[top[y]]) swap(x, y);x = fa[top[x]];}return dep[x] < dep[y] ? x : y;
}int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);n = read(), m = read();int rt = read();int x, y;for(int i = 1; i < n; i++) {x = read(), y = read();add(x, y);add(y, x);}dfs1(rt, 0);dfs2(rt, rt);for(int i = 1; i <= m; i++) {x = read(), y = read();printf("%d\n", solve(x, y));}return 0;
}

Tarjan离线求解

思想

本质就是利用了dfs的节点顺序,当我们正在递归两个节点的最近公共祖先时,显然这两个点是属于其子树的节点,那么当我们第一次遍历完两个需要求解的两个点时,其最近的尚未被完全遍历完子节点的节点就是他们两个的最近公共祖先。

代码

#include <bits/stdc++.h>using namespace std;typedef long long ll;
const int N = 5e5 + 10;int head[N], to[N << 1], nex[N << 1], cnt = 1;
int visit[N], fa[N], n, m;
int qhead[N], qto[N << 1], qnex[N << 1], qcnt = 1, qid[N << 1], ans[N];inline int read() {int f = 1, x = 0;char c = getchar();while(c > '9' || c < '0') {if(c == '-')    f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x;
}void add_edge(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++;
}void add_query(int x, int y, int w) {qto[qcnt] = y;qnex[qcnt] = qhead[x];qid[qcnt] = w;qhead[x] = qcnt++;
}int find(int rt) {return rt == fa[rt] ? rt : fa[rt] = find(fa[rt]);
}void tarjan(int rt, int f) {for(int i = head[rt]; i; i = nex[i]) {if(to[i] == f)  continue;tarjan(to[i], rt);fa[to[i]] = rt;}visit[rt] = 1;for(int i = qhead[rt]; i; i = qnex[i]) {if(!visit[qto[i]])  continue;ans[qid[i]] = find(qto[i]);}
}int main() {// freopen("in.txt", "r", stdin);n = read(), m = read();int rt = read();for(int i = 1; i < n; i++) {int x = read(), y = read();add_edge(x, y);add_edge(y, x);}for(int i = 1; i <= n; i++) fa[i] = i;for(int i = 1; i <= m; i++) {int x = read(), y = read();add_query(x, y, i);add_query(y, x, i);}tarjan(rt, 0);for(int i = 1; i <= m; i++)printf("%d\n", ans[i]);return 0;
}

ST表 + RMQ在线求解

思想

利用dfs的遍历,在遍历两个点的时候,一定会在中间返回到其最近公共祖先,这个时候的公共祖先也就是这两个点的遍历中的最小值。

代码

#include <bits/stdc++.h>using namespace std;typedef long long ll;inline ll read() {ll f = 1, x = 0;char c = getchar();while(c > '9' || c < '0') {if(c == '-')    f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x;
}const int N = 5e5 + 10;int head[N], to[N << 1], nex[N << 1], cnt = 1;
int id[N], tot, last;
int st[N << 2][30];void add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++;
}void dfs(int rt, int fa) {id[rt] = last = ++tot;st[tot][0] = rt;for(int i = head[rt]; i; i = nex[i]) {if(to[i] == fa) continue;dfs(to[i], rt);st[++tot][0] = rt;}
}int MIN(int a, int b) {return id[a] < id[b] ? a : b;
}int main() {// freopen("in.txt", "r", stdin);int n = read(), m = read(), rt = read();for(int i = 1; i < n; i++) {int x = read(), y = read();add(x, y);add(y, x);}dfs(rt, 0);int k = log(last) / log(2);for(int j = 1; j <= k; j++)for(int i = 1; i + (1 << j) - 1 <= last; i++)st[i][j] = MIN(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);for(int i = 1; i <= m; i++) {int x = read(), y = read();x = id[x], y = id[y];if(x > y)   swap(x, y);int k = log(y - x + 1) / log(2);printf("%d\n", MIN(st[x][k], st[y - (1 << k) + 1][k]));}return 0;
}

倍增

思想

类似于快速幂,通过二进制数的组合来达到log2log_2log2级别的优化,但是需要注意其中进制的枚举大小顺序。

代码

#include <bits/stdc++.h>using namespace std;typedef long long ll;inline ll read() {ll f = 1, x = 0;char c = getchar();while(c > '9' || c < '0') {if(c == '-')    f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x;
}const int N = 5e5 + 10;int head[N], to[N << 1], nex[N << 1], cnt = 1;
int fa[N][21], dep[N], n, m;void add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++;
}void dfs(int rt, int f) {dep[rt] = dep[f] + 1;fa[rt][0] = f;for(int i = 1; 1 << i <= dep[rt]; i++)//进制由小到大递推fa[rt][i] = fa[fa[rt][i - 1]][i - 1];for(int i = head[rt]; i; i = nex[i]) {if(to[i] == f)  continue;dfs(to[i], rt);}
}int LCA(int x, int y) {if(dep[x] < dep[y]) swap(x, y);for(int i = 20; i >= 0; i--)//进制由大到小开始组合,if(dep[fa[x][i]] >= dep[y])x = fa[x][i];if(x == y)  return x;//注意特判for(int i = 20; i >= 0; i--)//进制从小到大开始组合,if(fa[x][i] != fa[y][i])x = fa[x][i], y = fa[y][i];return fa[x][0];//这一步尤其考虑,为什么x, y不知LCA,而其父节点就一定是LCA,
}int main() {// freopen("in.txt", "r", stdin);int n = read(), m = read(), rt = read();for(int i = 1; i < n; i++) {int x = read(), y = read();add(x, y);add(y, x);}dfs(rt, 0);for(int i = 1; i <= m; i++) {int x = read(), y = read();printf("%d\n", LCA(x, y));}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314582.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HDU - 1998 奇数阶魔方

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个奇数nnn&#xff0c;构造一个nnn阶幻方。 3≤n≤193\le n\le 193≤n≤19 思路&#xff1a; 模板题了&#xff0c;直接构造一个幻方即可。 首先在第一行中间放一个111&#xff0c;之后每次看一下(…

Azure 物联网开发者体验 7 月更新:边缘计算开发工具,ARM64 设备开发,VS Code 容器化开发工具...

欢迎来到 Azure 物联网开发者体验的 7 月更新&#xff01;在本次发布中&#xff0c;微软为物联网开发人员提供了许多新的功能和改进&#xff01;物联网边缘计算开发工具正式发布Azure IoT Edge 于 2017 年发布。随着近两年的对边缘计算开发工具的不断开发与改善&#xff0c;Azu…

Tarjan缩点

Tarjan缩点 或许更好的阅读体验 P3387 【模板】缩点 思路 既然时缩点的模板&#xff0c;那么缩点自然少不了了&#xff0c;缩点后我们的到新的有向无环图&#xff0c;然后再利用这个无环图去找一条最大权值的路径&#xff0c;路径和即为答案。 我们改如何选取起点来避免不…

.NET中的值类型与引用类型

.NET中的值类型与引用类型这是一个常见面试题&#xff0c;值类型(Value Type)和引用类型(Reference Type)有什么区别&#xff1f;他们性能方面有什么区别&#xff1f;TL;DR&#xff08;先看结论&#xff09;值类型引用类型创建位置栈托管堆赋值时复制值复制引用动态内存分配无需…

Canada Cup 2016 C. Hidden Word 字符串构造

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个长度为272727的字符串sss&#xff0c;其中262626个字母每种都至少出现一次&#xff0c;让你构造一个213213213的矩阵&#xff0c;使得每个字母都出现一次&#xff0c;并且存在一条路径&#xff0c;经…

E:Johnny and Grandmaster

Johnny and Grandmaster 或许更好的阅读体验 思路 这道题就是把一组数分成两个集合&#xff0c;使这两个集合的对p的次方的和的差的最小值&#xff0c;也就是求sum1−sum2sum1 - sum2sum1−sum2得最小值&#xff0c; 由于结果过大我们可能需要对结果取模。那么这题得关键在于…

跨语言调用Hangfire定时作业服务

背景Hangfire允许您以非常简单但可靠的方式执行后台定时任务的工作。内置对任务的可视化操作。非常方便。但令人遗憾的是普遍都是业务代码和hagnfire服务本身聚合在一个程序中运行&#xff0c;极大的限制了hangfire的扩展和跨语言调用。所以萌生了开发一个支持restful api调用的…

Codeforces Round #453 (Div. 1) D. Weighting a Tree 构造 + dfs树

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一颗nnn个点的图&#xff0c;每个点都有一个点权cic_ici​&#xff0c;要求你给每个边赋一个权值kik_iki​&#xff0c;要求对于每个点与他相连的边的权值之和等于这个点的点权cic_ici​。 n≤1e5,n−1≤…

Codeforces Round #648 (Div. 2)(A, B, C, D)

Codeforces Round #648 (Div. 2) 或许更好的阅读体验 A:Matrix Game 思路 题意可以说是非常简单的&#xff0c;我们选定的格子的行列都不能存在1&#xff0c;可以发现我们可以放的格子一定是固定的&#xff0c;然后这题就变成了技术总共可以放多少个棋子了&#xff0c;所以…

可落地微服务on k8s的持续集成/部署方案

我们隔一流的软件生产工艺还有多远&#xff1f;在距离15000公里外&#xff0c;Amazon一年可以进行5000万次部署&#xff0c;在这一边某电商平台的研发部门里&#xff0c;让他们引以为傲的是他们正在进行“敏捷”开发模式&#xff0c;并对外号称他们是以每周为迭代来进行升级。时…

Codeforces Round #579 (Div. 3) F1. Complete the Projects (easy version) 排序 + 贪心

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 比较直观的想法就是对于bi≥0b_i\ge0bi​≥0的项目&#xff0c;我们将aia_iai​从小到大排序&#xff0c;让后依次加bib_ibi​&#xff0c;如果有取不到的&#xff0c;显然就无解。否则再看…

历久弥新 - 微软万亿市值背后的文化支撑(下)|DevOps案例研究

内容来源&#xff1a;DevOps案例深度研究-Microsoft文化支撑研究战队&#xff08;本文只展示部分PPT研究成果&#xff0c;更多细节请关注案例分享会&#xff0c;及本公众号。&#xff09;本案例内容贡献者&#xff1a;陈飞&#xff08;Topic Leader&#xff09;、陈雨卿、郭子奇…

Codeforces Round #579 (Div. 3) F2. Complete the Projects (hard version) dp + 贪心

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 排序方式跟easyeasyeasy版本的一样&#xff0c;但是hardhardhard版本是输出最多能选多少&#xff0c;所以我们对b<0b<0b<0的情况不能直接贪心的来选了&#xff0c;考虑用dpdpdp来…

D:Ehab the Xorcist

或许更好的阅读体验 Ehab the Xorcist 思路 刚看时确实是一脸懵&#xff0c;最怕的就是这种构造题了&#xff0c;然后细想好像能写啊。 判断不可行的条件&#xff0c;只有两种情况&#xff1a; 一、v<uv < uv<u是一定不可能的&#xff0c;一串数的异或值一定小于…

架构杂谈《九》

微服务与轻量级通信机制微服务架构是一种架构模式&#xff0c;它提倡将单一应用程序划分成一组小的服务&#xff0c;服务之间胡亮协调、互相配合&#xff0c;为用户提供最终价值。在微服务架构中&#xff0c;服务与服务之间通信时&#xff0c;通常是通过轻量级的通信机制&#…

Codeforces Round #585 (Div. 2) E. Marbles 状压dp + 逆序对

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 考虑数列最终的状态一定是相同颜色在一起&#xff0c;所以我们发现他的颜色是有顺序的&#xff01;显然可以用状压dpdpdp来枚举颜色的顺序&#xff0c;但是又有问题了&#xff0c;你怎么确…

E:Sleeping Schedule(DP)

或许更好的阅读体验 Sleeping Schedule 思路 这道题读题就感觉像时DPDPDP&#xff0c;读完题后更加坚定了&#xff0c;这是一道DPDPDP题目。 我们考虑状态转移方程&#xff0c;dp[i][j]dp[i][j]dp[i][j]表示在第iii次入睡时间是jjj的时候的时间最优值&#xff0c;所以显然有…

GitLab CI 自动部署netcore web api 到Docker

前端篇文章中&#xff0c;我们已经成功的将asp.net core webapi在Docker容器中运行&#xff0c;并且部署了一套自己的GitLab环境。.Net & Docker&#xff08;二&#xff09;5分钟快速用Docker部署你自己的GitLab.Net & Docker&#xff08;一&#xff09;在Docker容器上…

Codeforces Round #585 (Div. 2) F. Radio Stations 2-sat + 神仙建模

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 你现在有ppp种电台&#xff0c;有nnn对关系(x,y)(x,y)(x,y)代表xxx电台或yyy电台中至少有一个&#xff0c;mmm对关系(x,y)(x,y)(x,y)代表xxx电台或yyy电台中最多有一个&#xff0c;每个电台有两个参数li,ril…

C. Orac and LCM(数论lcm, gcd)

C. Orac and LCM 思路 题目非常简单&#xff0c;就是求gcd(lcm(i,j))foriinrange(n),forjinrange(n),i<jgcd(lcm_(i,\ j))\ for\ i\ in\ range(n),\ for\ j\ in\ range(n),\ i\ <\ jgcd(lcm(​i, j)) for i in range(n), for j in range(n), i < j 对于包含a1a_1a1…