Skip to content

Commit 4ab1844

Browse files
authored
Merge pull request #338 from hitonanode/rename-rerooting
Rename rerooting
2 parents c596b1f + 1cfa596 commit 4ab1844

File tree

4 files changed

+73
-67
lines changed

4 files changed

+73
-67
lines changed

tree/rerooting.hpp

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,77 +8,83 @@
88
// Reference:
99
// - https://atcoder.jp/contests/abc222/editorial/2749
1010
// - https://null-mn.hatenablog.com/entry/2020/04/14/124151
11-
template <class Edge, class St, class Ch, Ch (*merge)(Ch, Ch), Ch (*f)(St, int, Edge),
12-
St (*g)(Ch, int), Ch (*e)()>
11+
template <class Edge, class Subtree, class Children, Children (*rake)(Children, Children),
12+
Children (*add_edge)(Subtree, int, Edge), Subtree (*add_vertex)(Children, int),
13+
Children (*e)()>
1314
struct rerooting {
1415
int n_;
1516
std::vector<int> par, visited;
1617
std::vector<std::vector<std::pair<int, Edge>>> to;
17-
std::vector<St> dp_subtree;
18-
std::vector<St> dp_par;
19-
std::vector<St> dpall;
18+
19+
// dp_subtree[i] = DP(root=i, edge (i, par[i]) is removed).
20+
std::vector<Subtree> dp_subtree;
21+
22+
// dp_par[i] = DP(root=par[i], edge (i, par[i]) is removed). dp_par[root] is meaningless.
23+
std::vector<Subtree> dp_par;
24+
25+
// dpall[i] = DP(root=i, all edges exist).
26+
std::vector<Subtree> dpall;
27+
2028
rerooting(const std::vector<std::vector<std::pair<int, Edge>>> &to_)
2129
: n_(to_.size()), par(n_, -1), visited(n_, 0), to(to_) {
22-
for (int i = 0; i < n_; ++i) dp_subtree.push_back(g(e(), i));
30+
for (int i = 0; i < n_; ++i) dp_subtree.push_back(add_vertex(e(), i));
2331
dp_par = dpall = dp_subtree;
2432
}
2533

2634
void run_connected(int root) {
27-
if (visited[root]) return;
28-
visited[root] = 1;
35+
if (visited.at(root)) return;
36+
visited.at(root) = 1;
2937
std::vector<int> visorder{root};
3038

3139
for (int t = 0; t < int(visorder.size()); ++t) {
32-
int now = visorder[t];
33-
for (const auto &edge : to[now]) {
34-
int nxt = edge.first;
35-
if (visited[nxt]) continue;
40+
int now = visorder.at(t);
41+
for (const auto &[nxt, _] : to[now]) {
42+
if (visited.at(nxt)) continue;
3643
visorder.push_back(nxt);
37-
visited[nxt] = 1;
38-
par[nxt] = now;
44+
visited.at(nxt) = 1;
45+
par.at(nxt) = now;
3946
}
4047
}
4148

4249
for (int t = int(visorder.size()) - 1; t >= 0; --t) {
43-
int now = visorder[t];
44-
Ch ch = e();
45-
for (const auto &edge : to[now]) {
46-
int nxt = edge.first;
47-
if (nxt == par[now]) continue;
48-
ch = merge(ch, f(dp_subtree[nxt], nxt, edge.second));
50+
const int now = visorder.at(t);
51+
Children ch = e();
52+
for (const auto &[nxt, edge] : to.at(now)) {
53+
if (nxt != par.at(now)) ch = rake(ch, add_edge(dp_subtree.at(nxt), nxt, edge));
4954
}
50-
dp_subtree[now] = g(ch, now);
55+
dp_subtree.at(now) = add_vertex(ch, now);
5156
}
5257

53-
std::vector<Ch> left;
58+
std::vector<Children> left;
5459
for (int now : visorder) {
55-
int m = int(to[now].size());
60+
const int m = to.at(now).size();
5661
left.assign(m + 1, e());
5762
for (int j = 0; j < m; j++) {
58-
int nxt = to[now][j].first;
59-
const St &st = (nxt == par[now] ? dp_par[now] : dp_subtree[nxt]);
60-
left[j + 1] = merge(left[j], f(st, nxt, to[now][j].second));
63+
const auto &[nxt, edge] = to.at(now).at(j);
64+
const Subtree &st = (nxt == par.at(now) ? dp_par.at(now) : dp_subtree.at(nxt));
65+
left.at(j + 1) = rake(left.at(j), add_edge(st, nxt, edge));
6166
}
62-
dpall[now] = g(left.back(), now);
67+
dpall.at(now) = add_vertex(left.back(), now);
6368

64-
Ch rprod = e();
69+
Children rprod = e();
6570
for (int j = m - 1; j >= 0; --j) {
66-
int nxt = to[now][j].first;
67-
if (nxt != par[now]) dp_par[nxt] = g(merge(left[j], rprod), now);
71+
const auto &[nxt, edge] = to.at(now).at(j);
72+
73+
if (nxt != par.at(now)) dp_par.at(nxt) = add_vertex(rake(left.at(j), rprod), now);
6874

69-
const St &st = (nxt == par[now] ? dp_par[now] : dp_subtree[nxt]);
70-
rprod = merge(f(st, nxt, to[now][j].second), rprod);
75+
const Subtree &st = (nxt == par.at(now) ? dp_par.at(now) : dp_subtree.at(nxt));
76+
rprod = rake(add_edge(st, nxt, edge), rprod);
7177
}
7278
}
7379
}
7480

7581
void run() {
7682
for (int i = 0; i < n_; ++i) {
77-
if (!visited[i]) run_connected(i);
83+
if (!visited.at(i)) run_connected(i);
7884
}
7985
}
8086

81-
const St &get_subtree(int root_, int par_) const {
87+
const Subtree &get_subtree(int root_, int par_) const {
8288
if (par_ < 0) return dpall.at(root_);
8389
if (par.at(root_) == par_) return dp_subtree.at(root_);
8490
if (par.at(par_) == root_) return dp_par.at(par_);
@@ -87,13 +93,13 @@ struct rerooting {
8793
};
8894
/* Template:
8995
struct Subtree {};
90-
struct Child {};
96+
struct Children {};
9197
struct Edge {};
92-
Child e() { return Child(); }
93-
Child merge(Child x, Child y) { return Child(); }
94-
Child f(Subtree x, int ch_id, Edge edge) { return Child(); }
95-
Subtree g(Child x, int v_id) { return Subtree(); }
98+
Children e() { return Children(); }
99+
Children rake(Children x, Children y) { return Children(); }
100+
Children add_edge(Subtree x, int ch_id, Edge edge) { return Children(); }
101+
Subtree add_vertex(Children x, int v_id) { return Subtree(); }
96102
97103
vector<vector<pair<int, Edge>>> to;
98-
rerooting<Edge, Subtree, Child, merge, f, g, e> tree(to);
104+
rerooting<Edge, Subtree, Children, rake, add_edge, add_vertex, e> tree(to);
99105
*/

tree/rerooting.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ documentation_of: ./rerooting.hpp
77

88
- ここに記述する内容はリンク [1] で説明されていることとほぼ同等.
99
- 木の各頂点・各辺になんらかのデータ構造が載っている.
10-
- 根付き木について,各頂点 $v$ を根とする部分木に対して計算される `St` 型の情報を $X_v$ とする.また,各辺 $uv$ が持つ `Edge` 型の情報を $e_{uv}$ とする.
11-
- $X_v$ は $X_v = g\left(\mathrm{merge}\left(f(X\_{c\_1}, c\_1, e\_{v c\_1}), \dots, f(X\_{c\_k}, c\_k, e\_{v c\_k})\right), v \right)$ を満たす.ここで $c\_1, \dots, c\_k$ は $v$ の子の頂点たち.
12-
- $f(X\_v, v, e\_{uv})$ は $u$ の子 $v$ について `Ch` 型の情報を計算する関数.
13-
- $\mathrm{merge}(y\_1, \dots, y\_k)$ は任意個の `Ch` 型の引数の積を計算する関数
14-
- $g(y, v)$ は `Ch` 型の引数 $y$ をもとに頂点 $v$ における `St` 型の情報を計算する関数
15-
- `Ch` 型には結合法則が成立しなければならない.また, `Ch` 型の単位元を `e()` とする.
10+
- 根付き木について,各頂点 $v$ を根とする部分木に対して計算される `Subtree` 型の情報を $X_v$ とする.また,各辺 $uv$ が持つ `Edge` 型の情報を $e_{uv}$ とする.
11+
- $X_v$ は $X_v = \mathrm{add\_vertex}\left(\mathrm{rake}\left(\mathrm{add\_edge}(X\_{c\_1}, c\_1, e\_{v c\_1}), \dots, \mathrm{add\_edge}(X\_{c\_k}, c\_k, e\_{v c\_k})\right), v \right)$ を満たす.ここで $c\_1, \dots, c\_k$ は $v$ の子の頂点たち.
12+
- $\mathrm{add\_edge}(X\_v, v, e\_{uv})$ は $u$ の子 $v$ について `Children` 型の情報を計算する関数.
13+
- $\mathrm{add\_vertex}(y, v)$ は `Children` 型の引数 $y$ をもとに頂点 $v$ における `Subtree` 型の情報を計算する関数
14+
- $\mathrm{rake}(y\_1, \dots, y\_k)$ は任意個の `Children` 型の引数の積を計算する関数
15+
- $\mathrm{rake}()$ には結合法則が成立しなければならない.また, `Children` 型の単位元を `e()` とする.
1616
- 以上のような性質を満たすデータ構造を考えたとき,本ライブラリは森の各頂点 $r$ を根とみなしたときの連結成分に関する $X_r$ の値を全ての $r$ について線形時間で計算する.
1717

1818
## 使用方法(例)
@@ -23,29 +23,29 @@ struct Subtree {
2323
bool exist;
2424
int oneway, round;
2525
};
26-
struct Child {
26+
struct Children {
2727
bool exist;
2828
int oneway, round;
2929
};
30-
Child merge(Child x, Child y) {
30+
Children rake(Children x, Children y) {
3131
if (!x.exist) return y;
3232
if (!y.exist) return x;
33-
return Child{true, min(x.oneway + y.round, y.oneway + x.round), x.round + y.round};
33+
return Children{true, min(x.oneway + y.round, y.oneway + x.round), x.round + y.round};
3434
}
35-
Child f(Subtree x, int, tuple<>) {
35+
Children add_edge(Subtree x, int, tuple<>) {
3636
if (!x.exist) return {false, 0, 0};
3737
return {true, x.oneway + 1, x.round + 2};
3838
}
39-
Subtree g(Child x, int v) {
39+
Subtree add_vertex(Children x, int v) {
4040
if (x.exist) return {true, x.oneway, x.round};
4141
return {inD[v], 0, 0};
4242
return {false, 0, 0};
4343
}
44-
Child e() { return {false, 0, 0}; }
44+
Children e() { return {false, 0, 0}; }
4545

4646

4747
vector<vector<pair<int, tuple<>>>> to;
48-
rerooting<tuple<>, Subtree, Child, merge, f, g, e> tree(to);
48+
rerooting<tuple<>, Subtree, Children, rake, add_edge, add_vertex, e> tree(to);
4949
tree.run();
5050
for (auto x : tree.dpall) cout << x.oneway << '\n';
5151
```

tree/test/rerooting.aoj1595.test.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ using namespace std;
99
struct Subtree {
1010
int oneway, round;
1111
};
12-
struct Child {
12+
struct Children {
1313
int oneway, round;
1414
};
1515

16-
Child merge(Child x, Child y) {
17-
return Child{min(x.oneway + y.round, y.oneway + x.round), x.round + y.round};
16+
Children merge(Children x, Children y) {
17+
return Children{min(x.oneway + y.round, y.oneway + x.round), x.round + y.round};
1818
}
1919

20-
Child f(Subtree x, int, tuple<>) { return {x.oneway + 1, x.round + 2}; }
20+
Children add_edge(Subtree x, int, tuple<>) { return {x.oneway + 1, x.round + 2}; }
2121

22-
Subtree g(Child x, int) { return {x.oneway, x.round}; }
22+
Subtree add_vertex(Children x, int) { return {x.oneway, x.round}; }
2323

24-
Child e() { return {0, 0}; }
24+
Children e() { return {0, 0}; }
2525

2626
int main() {
2727
cin.tie(nullptr), ios::sync_with_stdio(false);
@@ -34,7 +34,7 @@ int main() {
3434
--u, --v;
3535
to[u].push_back({v, {}}), to[v].push_back({u, {}});
3636
}
37-
rerooting<tuple<>, Subtree, Child, merge, f, g, e> tree(to);
37+
rerooting<tuple<>, Subtree, Children, merge, add_edge, add_vertex, e> tree(to);
3838
tree.run();
3939
for (auto x : tree.dpall) cout << x.oneway << '\n';
4040
}

tree/test/rerooting.yuki1718.test.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,24 @@ struct Subtree {
1111
bool exist;
1212
int oneway, round;
1313
};
14-
struct Child {
14+
struct Children {
1515
bool exist;
1616
int oneway, round;
1717
};
18-
Child e() { return {false, 0, 0}; }
18+
Children e() { return {false, 0, 0}; }
1919

20-
Child merge(Child x, Child y) {
20+
Children merge(Children x, Children y) {
2121
if (!x.exist) return y;
2222
if (!y.exist) return x;
23-
return Child{true, min(x.oneway + y.round, y.oneway + x.round), x.round + y.round};
23+
return Children{true, min(x.oneway + y.round, y.oneway + x.round), x.round + y.round};
2424
}
2525

26-
Child f(Subtree x, int, tuple<>) {
26+
Children add_edge(Subtree x, int, tuple<>) {
2727
if (!x.exist) return e();
2828
return {true, x.oneway + 1, x.round + 2};
2929
}
3030

31-
Subtree g(Child x, int v) {
31+
Subtree add_vertex(Children x, int v) {
3232
if (x.exist or inD[v]) return {true, x.oneway, x.round};
3333
return {false, 0, 0};
3434
}
@@ -52,7 +52,7 @@ int main() {
5252
cin >> d;
5353
inD[d - 1] = 1;
5454
}
55-
rerooting<tuple<>, Subtree, Child, merge, f, g, e> tree(to);
55+
rerooting<tuple<>, Subtree, Children, merge, add_edge, add_vertex, e> tree(to);
5656
tree.run();
5757
for (auto x : tree.dpall) cout << x.oneway << '\n';
5858
}

0 commit comments

Comments
 (0)