hihoCoder#1069 最近公共祖先·三

原题地址

根据提示用Spase Table做

将Tree先展成List,因为数组长度等于边数的2倍,树中边数等于节点数-1,所以List数组只要开2倍节点数大小即可

WA了几次,原来是查询的时候出现左边界大于右边界的情况,所以这种情况要颠倒一下

代码:

 1 #include <iostream>
 2 #include <vector>
 3 #include <string>
 4 #include <map>
 5
 6 using namespace std;
 7
 8 #define MAX_NODE 100005
 9
10 int N, M;
11 map<string, int> a2i;
12 string i2a[MAX_NODE];
13 int traverse_path[MAX_NODE * 2];
14 int depth[MAX_NODE];
15 int st[MAX_NODE * 2][32]; // 保存的是节点编号
16 vector<int> child[MAX_NODE];
17 int last_position[MAX_NODE];
18 int path_length = 0;
19 int tree_size = 0;
20
21 void traverse(int r, int d) {
22   traverse_path[path_length++] = r;
23   depth[r] = d;
24   for (auto c : child[r]) {
25     traverse(c, d + 1);
26     traverse_path[path_length++] = r;
27   }
28   last_position[r] = path_length - 1;
29 }
30
31 void build() {
32   for (int i = 0; i < path_length; i++)
33     st[i][0] = traverse_path[i];
34
35   for (int j = 1; (1 << j) <= path_length; j++) {
36     for (int i = 0; i + (1 << j) <= path_length; i++) {
37       int a = st[i][j - 1];
38       int b = st[i + (1 << (j - 1))][j - 1];
39       st[i][j] = depth[a] < depth[b] ? a : b;
40     }
41   }
42 }
43
44 int query(int l, int r) {
45   if (l > r)
46     return query(r, l);
47   int len = r - l + 1;
48   int i = 0;
49   while ((1 << (i + 1)) <= len)
50     i++;
51   int a = st[l][i];
52   int b = st[r - (1 << i) + 1][i];
53   return depth[a] < depth[b] ? a : b;
54 }
55
56 int main() {
57   scanf("%d", &N);
58   for (int i = 0; i < N; i++) {
59     string a, b;
60     int ai, bi;
61     cin >> a >> b;
62     if (a2i.find(a) == a2i.end()) {
63       ai = a2i[a] = tree_size;
64       i2a[ai] = a;
65       tree_size++;
66     }
67     else
68       ai = a2i[a];
69     if (a2i.find(b) == a2i.end()) {
70       bi = a2i[b] = tree_size;
71       i2a[bi] = b;
72       tree_size++;
73     }
74     else
75       bi = a2i[b];
76     child[ai].push_back(bi);
77   }
78
79   traverse(0, 0);
80   build();
81
82   scanf("%d", &M);
83   while (M--) {
84     string a, b;
85     int ai, bi;
86     cin >> a >> b;
87     ai = a2i[a];
88     bi = a2i[b];
89     cout << i2a[query(last_position[ai], last_position[bi])] << endl;
90   }
91
92   return 0;
93 }
时间: 2024-08-26 21:40:45

hihoCoder#1069 最近公共祖先·三的相关文章

hihoCoder week17 最近公共祖先&#183;三 lca st表

记录dfs序列,dfn[tot] 记录第tot次访问的节点 然后查两点在dfs序中出现的第一次 id[u] id[v] 然后  找 dep[k] = min( dep[i] ) {i 属于 [id[u], id[v]]} 最后dfn[k] 就是所求.. 感觉弄来弄去 就是 在映射... 无非就是 求一段序列深度最小的节点编号 #include <bits/stdc++.h> using namespace std; const int N = 2e5+10; int n, cnt, tot,

hihoCoder_#1069_最近公共祖先&#183;三(RMQ-ST模板)

#1069 : 最近公共祖先·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho使用了Tarjan算法来优化了他们的"最近公共祖先"网站,但是很快这样一个离线算法就出现了问题:如果只有一个人提出了询问,那么小Hi和小Ho很难决定到底是针对这个询问就直接进行计算还是等待一定数量的询问一起计算.毕竟无论是一个询问还是很多个询问,使用离线算法都是只需要做一次深度优先搜索就可以了的. 那么问题就来了,如果每次计算都只针对一个询问进行的话

[ACM] hihocoder 1062 最近公共祖先&#183;一 (一般做法)

描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢? "为什么呢?"小Hi如是问道,在他的观察中小Ho已经沉迷这个网站一周之久了,甚至连他心爱的树玩具都弃置一边. "嘿嘿,小Hi,你快过来看!"小Ho招呼道. "你看,在这个对话框里输入我的名字,在另一个对话框里,输入你的名字,再点这个查询按钮,就可以查出来--什么!我们居然有同一个祖祖祖祖祖爷爷?" "诶,真是诶--这个网

[hiho 17]最近公共祖先 三

题目描述 这次是使用在线算法解决这个问题. 两个节点的最近公共祖先就是这两个节点的通路上深度最浅的那个节点. 可以通过一遍深搜把树转成数组:每次经过一个节点(无论是从父节点进入还是从子节点返回)时,把它放入数组.同时要记录每个节点在数组中最后一次出现的位置. 使用RMQ-ST算法预先计算2^k长度区间内深度最浅的节点编号. 对于每次询问,将其转换为两个区间段求解. #include <iostream> #include <algorithm> #include <cstri

hihocoder #1062 : 最近公共祖先&#183;一(小数据量 map+set模拟+标记检查 *【模板】思路 )

#1062 : 最近公共祖先·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢? “为什么呢?”小Hi如是问道,在他的观察中小Ho已经沉迷这个网站一周之久了,甚至连他心爱的树玩具都弃置一边. “嘿嘿,小Hi,你快过来看!”小Ho招呼道. “你看,在这个对话框里输入我的名字,在另一个对话框里,输入你的名字,再点这个查询按钮,就可以查出来……什么!我们居然有同

hihoCoder 1062 最近公共祖先&#183;一 最详细的解题报告

题目来源:最近公共祖先·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 题目描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢? “为什么呢?”小Hi如是问道,在他的观察中小Ho已经沉迷这个网站一周之久了,甚至连他心爱的树玩具都弃置一边. “嘿嘿,小Hi,你快过来看!”小Ho招呼道. “你看,在这个对话框里输入我的名字,在另一个对话框里,输入你的名字,再点这个查询按钮,就可以查出来……什么!我们居然有同一

hihoCoder - 1062 - 最近公共祖先&#183;一 (树的最近公共祖先问题!)

#1062 : 最近公共祖先·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢? "为什么呢?"小Hi如是问道,在他的观察中小Ho已经沉迷这个网站一周之久了,甚至连他心爱的树玩具都弃置一边. "嘿嘿,小Hi,你快过来看!"小Ho招呼道. "你看,在这个对话框里输入我的名字,在另一个对话框里,输入你的名字,再点这个查询

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

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

【hihoCoder第十七周】最近公共祖先&#183;三

之前就写的是离线算法.思路就是先序一遍树,记录层数,然后高效RMQ就好.ST和线段树都能过. 以后有时间将之前的在线算法补上. #include <bits/stdc++.h> using namespace std; #define MAXN 100005 #define MAXM 105 #define inf 0x7ffffff int n; struct Edge { int v, next; } edge[MAXN]; int head[MAXN]; int e; void addE