LCA问题【RMQ+Tarjan】

摘要:
树上的LCA最近共同祖先问题lrj的紫色书提供了一种将LCA问题转化为RMQ问题的方法,即dfs一次处理一个序列,first(u)表示u的下标,u和v的最近共同祖先的下标是RMQ(first(u),first))。LCA->RMQ(在线处理):1#包括<bits/stdc++。h>2使用namespacestd;3约束N=

LCA-求树上两点最近公共祖先问题

lrj的紫书上提供了一种将LCA问题转化为RMQ问题的方法,即dfs一次处理出一个序列,first(u)代表u第一次出现的下标,则对于u,v的最近公共祖先的下标即为RMQ(first(u), first(v))。

LCA->RMQ(在线处理):

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 40010, M = 25;
 4 int ver[2*N], R[2*N], first[N], dir[N], dp[2*N][M], tot;
 5 /*ver[i]保存下标为i的结点编号,R[i]为下标为i的结点深度,first[i]为编号为i的结点第一次出现的下标,
 6 dp[i][j]为起始下标为i,长度为1<<j的区间的最小深度的结点的下标*/
 7 bool vis[N];
 8 struct Node {
 9     int to, w;
10 };
11 vector<Node> G[N];
12 
13 void dfs(int u, int dep) {
14     vis[u] = true; ver[++tot] = u; first[u] = tot; R[tot] = dep;
15     for (int i = 0; i < G[u].size(); ++i) {
16         int v = G[u][i].to, w = G[u][i].w;
17         dir[v] = dir[u] + w;  
18         if (vis[v]) continue;
19         dfs(v, dep+1);
20         ver[++tot] = u; R[tot] = dep; 
21     }
22 }
23 
24 void RMQ_init(int l, int r) {
25     for (int i = l; i <= r; ++i) dp[i][0] = ver[i];
26     for (int k = 1; (1<<k) <= r-l+1; ++k)
27         for (int i = l; i + (1<<k) <= r; ++i) {
28             int a = dp[i][k-1], b = dp[i+(1<<(k-1))][k-1];
29             if (R[a] > R[b]) dp[i][k] = b;
30             else dp[i][k] = a;
31         }
32 }
33 
34 int RMQ(int l, int r) {
35     int k = 0;
36     while ((1<<(k+1)) <= r-l+1) ++k;
37     int a = dp[l][k], b = dp[r-(1<<k)][k];
38     if (R[a] > R[b]) return b;
39     else return a; 
40 }
41 
42 int LCA(int u, int v) {
43     int x = first[u], y = first[v];
44     if (x > y) swap(x, y);
45     int res = RMQ(x, y);
46     return ver[res];
47 }
48 
49 int main() {
50     int n;
51     while (cin >> n) {
52         memset(dir, 0, sizeof(dir));
53         memset(vis, 0, sizeof(vis));
54         for (int i = 1; i <= n; ++i) G[i].clear();
55         tot = 0;
56         int a, b, c;
57         for (int i = 1; i < n; ++i) {
58             cin >> a >> b >> c;
59             G[a].push_back(Node{b, c});
60         }
61         dfs(1, 1);
62         RMQ_init(1, 2*n-1);
63         int q, u, v;
64         cin >> q;
65         while (q--) {
66             cin >> u >> v;
67             cout << LCA(u, v) << endl;
68         }
69     }
70 
71     return 0;
72 }

Tarjan算法(离线处理):

具体思想不再阐述,下图代表处理编号10的结点的询问时的状态(同色代表处于同一个集合);

LCA问题【RMQ+Tarjan】第1张

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 10005;
 4 int p[maxn], anc[maxn];
 5 bool vis[maxn];
 6 vector<int> G[maxn];
 7 vector<int> q[maxn];
 8 
 9 int find(int x) {return x == p[x] ? x : p[x] = find(p[x]);}
10 
11 void Union(int x, int y) {
12     x = find(x); y = find(y);
13     if (x == y) return;
14     p[y] = x;
15 }
16 
17 void LCA(int u) {
18     anc[u] = u;
19     for (int i = 0; i < G[u].size(); ++i) {
20         int v = G[u][i];
21         LCA(v);
22         Union(u, v);
23         anc[find(u)] = u;
24     }
25     vis[u] = true;
26     for (int i = 0; i < q[u].size(); ++i) {
27         int v = q[u][i];
28         if (!vis[v]) continue;
29         printf("LCA(%d, %d): %d
", u, v, anc[find(v)]);
30     }
31 }
32 
33 int main() {
34     int n;
35     while (~scanf("%d", &n)) {
36         int a, b, k;
37         memset(vis, 0, sizeof(vis));
38         for (int i = 1; i <= n; ++i) G[i].clear(), p[i] = i;
39         for (int i = 1; i < n; ++i) {
40             scanf("%d%d", &a, &b);
41             G[a].push_back(b);
42         }
43         scanf("%d", &k);
44         for (int i = 0; i < k; ++i) q[i].clear();
45         while (k--) {
46             scanf("%d%d", &a, &b);
47             q[a].push_back(b);
48             q[b].push_back(a);
49         }
50         LCA(1);
51     }
52 
53     return 0;
54 }

免责声明:文章转载自《LCA问题【RMQ+Tarjan】》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇mysql 存储过程权限相关unittest 执行airtest 脚本下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

OC输入输出

输入:scanf,注意scanf的指示符不加@ #import <Foundation/Foundation.h> #import "MyFirstClass.h" int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"输入:");...

最小有向生成树

先看一下lrj的大白书上的讲解 emm。。。我是看完之后直接看的模板题代码。。。居然看懂。。。行吧。。 就是先判断 能不能联通  如能联通 就求出每个点的最小前驱边  求完之后 看有没有环 如有环 缩点更新 然后一直重复 直至无环且联通。。   //邻接矩阵模板: #include <iostream> #include <cstdio...

单色三角形(hdu-5072

  单色三角形模型:空间里有n个点,任意三点不共线。每两个点之间都用红色或者黑色线段链接。如果一个三角形的三条边同色,责成这个三角形是单色三角形。对于给定的红色线段列表,找出单色三角形的个数。   分析:对于一个顶点,设他连红线的点又x个,那么它脸黑线的点有(n-1-x)个,那么能组成的三角形有x*(n-1-x)个,因为每个点都会遍历,所以得到的结果会重复...

ATM管理系统(C语言)

1. 作业信息 这个作业属于哪个课程 软件工程 这个作业要求在哪里 作业要求 学号 3180701312 2.题目 编写一个ATM管理系统,语言不限,要求应包括以下主要功能: (1)开户,销户 (2)查询账户余额 (3)存款 (4)取款 (5)转账(一个账户转到另一个账户)等... 3. 代码提交与运行截图 3.1 源代码 (1)头文件...

[2020牛客暑期多校训练营(第一场)虚树 Infinite Tree]

2020牛客暑期多校训练营(第一场)虚树 Infinite Tree 题解参考博客:https://blog.nowcoder.net/n/df889adfaf824d50ad2291f4d2eb04a2?&toCommentId=6480068 题目大意: 定义 (mindiv(n)) 是 (n) 最小的大于1的约数,对于每一个 (i),(1&l...

splay模板 指针版&amp;amp;splay被卡祭

普通平衡树板子 参考了大佬博客 访问空指针会出错,我用了一个nil代替他。(c++是谁设计的我还得把结构体定义在外面真难受) #include<bits/stdc++.h> using namespace std; typedef pair<int,int> pii; #define forg(i,x) for(int i=firs...