重链剖分

fsjhhh Lv2

重链剖分

洛谷P3384:重链剖分加线段树

  • 重儿子:父亲节点的所有儿子中子树结点数目最多(size最大)的结点;

  • 轻儿子:父亲节点中除了重儿子以外的儿子;

  • 重边:父亲结点和重儿子连成的边;

  • 轻边:父亲节点和轻儿子连成的边;

  • 重链:由多条重边连接而成的路径;

  • 轻链:由多条轻边连接而成的路径;

  • : 树的大小

  • : 点的深度

  • : 点重链的链头,如果是轻链则是本身

  • : 点的父亲节点

  • : 点的进入时间(第一次出现的dfs序)

  • : 点的出去时间(最后一次出现的dfs序)

  • : 对应的点

  • : 为邻接表,第一个是重儿子

如果为边权,需要边权转点权,即将边权给予远离根的节点,计算边权之和时去掉转后的点权去掉即可

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
struct HLD {
int n;
std::vector<int> siz, top, dep, parent, in, out, seq;
std::vector<std::vector<int>> adj;
int cur;

HLD() {}
HLD(int n) {
init(n);
}
void init(int n) {
this->n = n;
siz.resize(n);
top.resize(n);
dep.resize(n);
parent.resize(n);
in.resize(n);
out.resize(n);
seq.resize(n);
cur = 0;
adj.assign(n, {});
}
void addEdge(int u, int v) {
adj[u].push_back(v);
adj[v].push_back(u);
}
void work(int root = 0) {
top[root] = root;
dep[root] = 0;
parent[root] = -1;
dfs1(root);
dfs2(root);
}
void dfs1(int u) {
if (parent[u] != -1) {
adj[u].erase(std::find(adj[u].begin(), adj[u].end(), parent[u]));
}

siz[u] = 1;
for (auto &v : adj[u]) {
parent[v] = u;
dep[v] = dep[u] + 1;
dfs1(v);
siz[u] += siz[v];
if (siz[v] > siz[adj[u][0]]) {
std::swap(v, adj[u][0]);
}
}
}
void dfs2(int u) {
in[u] = cur++;
seq[in[u]] = u;
for (auto v : adj[u]) {
top[v] = v == adj[u][0] ? top[u] : v;
dfs2(v);
}
out[u] = cur;
}
int lca(int u, int v) { // 最近公共祖先
while (top[u] != top[v]) {
if (dep[top[u]] > dep[top[v]]) {
u = parent[top[u]];
} else {
v = parent[top[v]];
}
}
return dep[u] < dep[v] ? u : v;
}

int dist(int u, int v) { // 两点间的距离
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}

int jump(int u, int k) { // u点向上跳k步到达的点
if (dep[u] < k) {
return -1;
}

int d = dep[u] - k;

while (dep[top[u]] > d) {
u = parent[top[u]];
}

return seq[in[u] - dep[u] + d];
}

bool isAncester(int u, int v) { // u是否是v的祖先节点
return in[u] <= in[v] && in[v] < out[u];
}

int rootedParent(int u, int v) { // 以v为跟的树中u节点的父节点
std::swap(u, v);
if (u == v) {
return u;
}
if (!isAncester(u, v)) {
return parent[u];
}
auto it = std::upper_bound(adj[u].begin(), adj[u].end(), v, [&](int x, int y) {
return in[x] < in[y];
}) - 1;
return *it;
}

int rootedSize(int u, int v) { // 以u为根的树中v子树的大小
if (u == v) {
return n;
}
if (!isAncester(v, u)) {
return siz[v];
}
return n - siz[rootedParent(u, v)];
}

int rootedLca(int a, int b, int c) { // (a, b, c)的最近公共祖先
return lca(a, b) ^ lca(b, c) ^ lca(c, a);
}
};
  • 标题: 重链剖分
  • 作者: fsjhhh
  • 创建于 : 2024-02-26 16:50:35
  • 更新于 : 2024-08-12 13:38:21
  • 链接: https://fsjhhh.github.io/2024/02/26/重链剖分/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
此页目录
重链剖分