-
Notifications
You must be signed in to change notification settings - Fork 12
/
rerooting_with_edge.cpp
207 lines (181 loc) · 5.81 KB
/
rerooting_with_edge.cpp
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
//
// 抽象化した全方位木 DP (木 DP パートで辺に関する処理も行う場合)
//
// verified:
// EDPC V - Subtree
// https://atcoder.jp/contests/dp/tasks/dp_v
//
// AtCoder ABC 348 E - Minimize Sum of Distances
// https://atcoder.jp/contests/abc348/tasks/abc348_e
//
/*
通常の木 DP において、頂点 v を根とする部分根付き木に関する再帰関数 rec(v) について、
1. res = IDENTITY
2. 頂点 v の各子頂点 v2 (その辺を e とする) に対して:res = MERGE(res, ADDEDGE(e, rec(v2)))
3. return ADDNODE(v, res)
というような更新を行うものとする。
このような木 DP を全方位木 DP へと拡張する。
*/
#include <bits/stdc++.h>
using namespace std;
// re-rooting
template<class Monoid, class Edge> struct ReRooting {
using Graph = vector<vector<Edge>>;
using GetIdFunc = function<int(Edge)>;
using AddEdgeFunc = function<Monoid(Edge, Monoid)>;
using MergeFunc = function<Monoid(Monoid, Monoid)>;
using AddNodeFunc = function<Monoid(int, Monoid)>;
// core member
Graph G;
Monoid IDENTITY;
GetIdFunc GETID;
AddEdgeFunc ADDEDGE;
MergeFunc MERGE;
AddNodeFunc ADDNODE;
// inner data
vector<vector<Monoid>> dp;
// constructor
ReRooting() {}
ReRooting(const Graph &g, const Monoid &identity, const GetIdFunc &getid,
const AddEdgeFunc &addedge, const MergeFunc &merge, const AddNodeFunc &addnode) {
G = g;
IDENTITY = identity;
GETID = getid;
ADDEDGE = addedge;
MERGE = merge;
ADDNODE = addnode;
build();
}
// re-looting dp
Monoid rec(int v, int p) {
Monoid res = IDENTITY;
dp[v].assign(G[v].size(), IDENTITY);
for (int i = 0; i < G[v].size(); ++i) {
int v2 = GETID(G[v][i]);
if (v2 == p) continue;
dp[v][i] = rec(v2, v);
res = MERGE(res, ADDEDGE(G[v][i], dp[v][i]));
}
return ADDNODE(v, res);
}
void rerec(int v, int p, Monoid pval) {
for (int i = 0; i < G[v].size(); ++i) {
int v2 = GETID(G[v][i]);
if (v2 == p) {
dp[v][i] = pval;
continue;
}
}
vector<Monoid> left(G[v].size() + 1, IDENTITY);
vector<Monoid> right(G[v].size() + 1, IDENTITY);
for (int i = 0; i < G[v].size(); ++i) {
int ri = (int)G[v].size() - i - 1;
left[i + 1] = MERGE(left[i], ADDEDGE(G[v][i], dp[v][i]));
right[i + 1] = MERGE(right[i], ADDEDGE(G[v][ri], dp[v][ri]));
}
for (int i = 0; i < G[v].size(); ++i) {
int v2 = GETID(G[v][i]), ri = (int)G[v].size() - i - 1;
if (v2 == p) continue;
Monoid pval2 = MERGE(left[i], right[ri]);
rerec(v2, v, ADDNODE(v, pval2));
}
}
void build() {
dp.assign(G.size(), vector<Monoid>());
int root = 0;
rec(root, -1);
rerec(root, -1, IDENTITY);
}
// getter
Monoid get(int v) {
Monoid res = IDENTITY;
for (int i = 0; i < G[v].size(); ++i) {
res = MERGE(res, ADDEDGE(G[v][i], dp[v][i]));
}
return ADDNODE(v, res);
}
// dump
friend constexpr ostream& operator << (ostream &os, const ReRooting<Monoid, Edge> &rr) {
for (int v = 0; v < rr.G.size(); ++v) {
for (int i = 0; i < rr.G[v].size(); ++i) {
os << v << " -> " << rr.GETID(rr.G[v][i]) << ": " << rr.dp[v][i] << endl;
}
}
return os;
}
};
//------------------------------//
// Examples
//------------------------------//
// TDPC V - Subtree
void TDPC_V() {
int N, M;
cin >> N >> M;
using Edge = int;
using Graph = vector<vector<Edge>>;
Graph G(N);
for (int i = 0; i < N - 1; ++i) {
int x, y;
cin >> x >> y;
--x, --y;
G[x].push_back(y);
G[y].push_back(x);
}
using Monoid = long long;
Monoid identity = 1;
auto getid = [&](Edge e) -> int { return e; };
auto addedge = [&](Edge e, Monoid a) -> Monoid { return a; };
auto merge = [&](Monoid a, Monoid b) -> Monoid { return a * b % M; };
auto addnode = [&](int v, Monoid a) -> Monoid { return (a + 1) % M; };
ReRooting<Monoid, Edge> rr(G, identity, getid, addedge, merge, addnode);
//cout << rr << endl;
for (int v = 0; v < N; ++v) {
cout << (rr.get(v) + M - 1) % M << endl;
}
}
// ABC 348 E - Minimize Sum of Distances
void ABC_348_E() {
using Edge = int;
using Graph = vector<vector<Edge>>;
int N;
cin >> N;
Graph G(N);
vector<long long> C(N);
for (int i = 0; i < N - 1; ++i) {
int a, b;
cin >> a >> b;
--a, --b;
G[a].push_back(b);
G[b].push_back(a);
}
for (int i = 0; i < N; ++i) cin >> C[i];
using Monoid = pair<long long, long long>; // (siz, sum)
Monoid IDENTITY = Monoid(-1, -1);
auto GETID = [&](Edge e) { return e; };
auto ADDEDGE = [&](Edge e, Monoid a) {
return a;
};
auto MERGE = [&](Monoid a, Monoid b) {
if (a.first == -1) return b;
else if (b.first == -1) return a;
else return Monoid(a.first + b.first, a.second + b.second);
};
auto ADDNODE = [&](int v, Monoid a) {
Monoid res(C[v], C[v]);
if (a.first == -1) return res;
res.first += a.first;
res.second += a.first + a.second;
return res;
};
ReRooting<Monoid, Edge> rr(G, IDENTITY, GETID, ADDEDGE, MERGE, ADDNODE);
long long res = 1LL << 62;
for (int v = 0; v < N; ++v) {
auto tmp = rr.get(v);
res = min(res, tmp.second - tmp.first);
}
cout << res << endl;
}
int main() {
TDPC_V();
//ABC_348_E();
}