forked from spaghetti-source/algorithm
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathleast_common_ancestor_tarjan.cc
More file actions
104 lines (99 loc) · 2.46 KB
/
Copy pathleast_common_ancestor_tarjan.cc
File metadata and controls
104 lines (99 loc) · 2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//
// Offline least common ancestor
//
// Description
// For a rooted tree T, LCA(u,v) is a vertex u
// that is the deepest node that is a common ancestor of u and v.
// It computes all lcas of (u_j, v_j) for v = 1, ..., q.
//
// Algorithm
// Tarjan's dfs and union-find.
//
// Complexity:
// O((m+q) a(n)), where a(n) is the inverse Ackermann function.
//
// Verified:
// SPOJ14932
#include <iostream>
#include <vector>
#include <cstdio>
#include <unordered_map>
#include <algorithm>
using namespace std;
#define fst first
#define snd second
#define all(c) ((c).begin()), ((c).end())
struct graph {
int n;
vector<vector<int>> adj;
graph(int n = 0) : n(n), adj(n) { }
void add_edge(int src, int dst) {
n = max(n, max(src, dst)+1);
adj.resize(n);
adj[src].push_back(dst);
}
struct query { int u, v, a; };
struct union_find {
vector<int> p;
union_find(int n) : p(n, -1) { };
bool unite(int u, int v) {
if ((u = root(u)) == (v = root(v))) return false;
if (p[u] > p[v]) swap(u, v);
p[u] += p[v]; p[v] = u;
return true;
}
int root(int u) { return p[u] < 0 ? u : p[u] = root(p[u]); }
};
void lca(vector<query> &queries) {
vector<vector<query*>> Q(n);
for (auto &q: queries) {
Q[q.u].push_back(&q);
Q[q.v].push_back(&q);
}
union_find uf(n);
vector<int> anc(n), color(n);
iota(all(anc), 0);
function<void (int)> rec = [&](int u) {
for (auto v: adj[u]) {
rec(v);
uf.unite(u, v);
anc[uf.root(u)] = u;
}
color[u] = 1;
for (auto it: Q[u]) {
if (it->u != u) swap(it->u, it->v);
if (color[it->v] == 1) it->a = anc[uf.root(it->v)];
}
};
vector<int> deg(n);
for (int u = 0; u < n; ++u)
for (auto v: adj[u])
++deg[v];
for (int u = 0; u < n; ++u)
if (deg[u] == 0) rec(u);
}
};
int main() {
int ncase; scanf("%d", &ncase);
for (int icase = 0; icase < ncase; ++icase) {
printf("Case %d:\n", icase+1);
int n; scanf("%d", &n);
graph g(n);
for (int i = 0; i < n; ++i) {
int k; scanf("%d", &k);
for (int j = 0; j < k; ++j) {
int l; scanf("%d", &l);
g.add_edge(i, l-1);
}
}
int q; scanf("%d", &q);
vector<graph::query> queries;
for (int i = 0; i < q; ++i) {
int u, v; scanf("%d %d", &u, &v);
queries.push_back({u-1, v-1, -1});
}
g.lca(queries);
for (auto q: queries)
printf("%d\n", q.a+1);
}
}