Skip to content

Commit b8961e5

Browse files
committed
Add static top tree
1 parent c751c5b commit b8961e5

File tree

2 files changed

+321
-0
lines changed

2 files changed

+321
-0
lines changed

data_structure/static_toptree.hpp

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
#pragma once
2+
#include <cassert>
3+
#include <utility>
4+
#include <vector>
5+
6+
// Structure of static top tree
7+
// https://atcoder.jp/contests/abc351/submissions/52777033
8+
struct static_toptree_structure {
9+
enum NodeType {
10+
Vertex,
11+
Compress,
12+
Rake,
13+
AddEdge,
14+
AddVertex,
15+
};
16+
17+
const std::vector<std::vector<int>> &to;
18+
std::vector<int> par;
19+
std::vector<int> heavy_child; // heavy_child[i] = child of i on heavy path
20+
21+
// toptree data
22+
int stt_root = -1;
23+
std::vector<int> P, L, R;
24+
std::vector<NodeType> T;
25+
26+
private:
27+
int hld_dfs(int now, int prv) {
28+
int sz = 1, max_sz = 0;
29+
for (int nxt : to.at(now)) {
30+
if (nxt == prv) continue;
31+
par.at(nxt) = now;
32+
int sub_sz = hld_dfs(nxt, now);
33+
sz += sub_sz;
34+
if (max_sz < sub_sz) max_sz = sub_sz, heavy_child.at(now) = nxt;
35+
}
36+
return sz;
37+
}
38+
39+
int create(int k, int l, int r, NodeType t) {
40+
if (k == -1) {
41+
k = P.size();
42+
P.push_back(-1), L.push_back(l), R.push_back(r), T.push_back(t);
43+
} else {
44+
P.at(k) = -1, L.at(k) = l, R.at(k) = r, T.at(k) = t;
45+
}
46+
47+
if (l != -1) P.at(l) = k;
48+
if (r != -1) P.at(r) = k;
49+
50+
return k;
51+
}
52+
53+
std::pair<int, int> merge(const std::vector<std::pair<int, int>> &a, NodeType t) {
54+
if (a.size() == 1) return a.front();
55+
56+
int u = 0;
57+
for (auto &[idx, sz] : a) u += sz;
58+
59+
std::vector<std::pair<int, int>> left, right;
60+
for (const auto &[idx, sz] : a) {
61+
(u > sz ? left : right).emplace_back(idx, sz), u -= sz * 2;
62+
}
63+
64+
auto [left_idx, left_sz] = merge(left, t);
65+
auto [right_idx, right_sz] = merge(right, t);
66+
67+
return {create(-1, left_idx, right_idx, t), left_sz + right_sz};
68+
}
69+
70+
std::pair<int, int> compress(int i) {
71+
std::vector<std::pair<int, int>> chs{add_vertex(i)};
72+
while (heavy_child.at(i) != -1) {
73+
i = heavy_child.at(i);
74+
chs.push_back(add_vertex(i));
75+
}
76+
77+
return merge(chs, Compress);
78+
}
79+
80+
std::pair<int, int> rake(int i) {
81+
std::vector<std::pair<int, int>> chs;
82+
for (int j : to.at(i)) {
83+
if (j == par.at(i) or j == heavy_child.at(i)) continue;
84+
chs.push_back(add_edge(j));
85+
}
86+
87+
return chs.empty() ? std::make_pair(-1, 0) : merge(chs, Rake);
88+
}
89+
90+
std::pair<int, int> add_edge(int i) {
91+
auto [c, sz] = compress(i);
92+
return {create(-1, c, -1, AddEdge), sz};
93+
}
94+
95+
std::pair<int, int> add_vertex(int i) {
96+
auto [c, sz] = rake(i);
97+
return {create(i, c, -1, c == -1 ? Vertex : AddVertex), sz + 1};
98+
}
99+
100+
public:
101+
static_toptree_structure(const std::vector<std::vector<int>> &to, int root) : to(to) {
102+
103+
const int n = to.size();
104+
105+
par.assign(n, -1), heavy_child.assign(n, -1);
106+
107+
hld_dfs(root, -1);
108+
109+
P.assign(n, -1), L.assign(n, -1), R.assign(n, -1), T.assign(n, Vertex);
110+
111+
stt_root = compress(root).first;
112+
}
113+
114+
int size() const { return P.size(); }
115+
116+
// Top tree の帰りがけ順に f() を呼ぶ
117+
// データの初期化などに利用可能
118+
template <class Callback> void dfs_postorder(Callback f) const {
119+
auto rec = [&](auto &&self, int now) -> void {
120+
if (L.at(now) != -1) self(self, L.at(now));
121+
if (R.at(now) != -1) self(self, R.at(now));
122+
f(now);
123+
};
124+
rec(rec, stt_root);
125+
}
126+
127+
// Top tree の v から根(!= もとの木の根)までのパス上で f() を呼ぶ
128+
// 一点更新などに利用可能
129+
template <class Callback> void path_to_root(int v, Callback f) const {
130+
while (v != -1) f(v), v = P.at(v);
131+
}
132+
};
133+
134+
// Static top tree
135+
template <class TreeDP> struct static_toptree {
136+
137+
using Point = typename TreeDP::Point;
138+
using Path = typename TreeDP::Path;
139+
140+
const static_toptree_structure &stts;
141+
TreeDP &tree_dp;
142+
143+
std::vector<Point> point;
144+
std::vector<Path> path;
145+
146+
private:
147+
void _update(int i) {
148+
if (stts.T.at(i) == static_toptree_structure::Vertex) {
149+
path.at(i) = tree_dp.vertex(i);
150+
} else if (stts.T.at(i) == static_toptree_structure::Compress) {
151+
path.at(i) = tree_dp.compress(path.at(stts.L.at(i)), path.at(stts.R.at(i)));
152+
} else if (stts.T.at(i) == static_toptree_structure::Rake) {
153+
point.at(i) = tree_dp.rake(point.at(stts.L.at(i)), point.at(stts.R.at(i)));
154+
} else if (stts.T.at(i) == static_toptree_structure::AddEdge) {
155+
point.at(i) = tree_dp.add_edge(path.at(stts.L.at(i)));
156+
} else if (stts.T.at(i) == static_toptree_structure::AddVertex) {
157+
path.at(i) = tree_dp.add_vertex(point.at(stts.L.at(i)), i);
158+
} else {
159+
assert(false);
160+
}
161+
}
162+
163+
public:
164+
static_toptree(const static_toptree_structure &stts, TreeDP &tree_dp)
165+
: stts(stts), tree_dp(tree_dp), point(stts.size()), path(stts.size()) {
166+
stts.dfs_postorder([&](int k) { _update(k); });
167+
}
168+
169+
void set(int i) {
170+
stts.path_to_root(i, [&](int k) { _update(k); });
171+
}
172+
173+
Path all_prod() const { return path.at(stts.stt_root); }
174+
175+
// Not verified yet
176+
Path get_subtree(int i) const {
177+
Path res = path.at(i);
178+
while (true) {
179+
const int p = stts.P.at(i);
180+
if (p == -1 or stts.T.at(p) != static_toptree_structure::Compress) break;
181+
182+
if (stts.L.at(p) == i) res = tree_dp.compress(res, path.at(stts.R.at(p)));
183+
i = p;
184+
}
185+
186+
return res;
187+
}
188+
};
189+
190+
/*
191+
struct tree_dp {
192+
struct Point; // Point Cluster
193+
struct Path; // Path Cluster
194+
195+
Path vertex(int i);
196+
197+
Path compress(const Path &p, const Path &c);
198+
199+
Point rake(const Point &l, const Point &r);
200+
201+
Point add_edge(const Path &d);
202+
203+
Path add_vertex(const Point &d, int i);
204+
};
205+
206+
vector<vector<int>> to(n);
207+
int root;
208+
209+
const static_toptree_structure stts(to, root);
210+
211+
tree_dp dp;
212+
static_toptree tree(stts, dp);
213+
*/
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#define PROBLEM "https://judge.yosupo.jp/problem/point_set_tree_path_composite_sum_fixed_root"
2+
3+
#include "../static_toptree.hpp"
4+
5+
#include <iostream>
6+
#include <vector>
7+
using namespace std;
8+
9+
#include <atcoder/modint>
10+
using mint = atcoder::modint998244353;
11+
12+
struct tree_dp {
13+
vector<int> A;
14+
vector<mint> parB;
15+
vector<mint> parC;
16+
17+
// Point Cluster
18+
struct Point {
19+
mint n;
20+
mint sum;
21+
};
22+
23+
// Path Cluster
24+
struct Path {
25+
mint n;
26+
mint sum;
27+
28+
mint b;
29+
mint c;
30+
};
31+
32+
Path vertex(int i) { return {1, A.at(i) * parB.at(i) + parC.at(i), parB.at(i), parC.at(i)}; }
33+
34+
static Path compress(const Path &p, const Path &c) {
35+
return {p.n + c.n, p.sum + c.sum * p.b + c.n * p.c, c.b * p.b, p.c + c.c * p.b};
36+
}
37+
38+
static Point rake(const Point &l, const Point &r) { return {l.n + r.n, l.sum + r.sum}; }
39+
40+
static Point add_edge(const Path &d) { return {d.n, d.sum}; }
41+
42+
Path add_vertex(const Point &d, int i) {
43+
return {d.n + 1, (d.sum + A.at(i)) * parB.at(i) + (d.n + 1) * parC.at(i), parB.at(i),
44+
parC.at(i)};
45+
}
46+
};
47+
48+
int main() {
49+
cin.tie(nullptr), ios::sync_with_stdio(false);
50+
51+
int N, Q;
52+
cin >> N >> Q;
53+
54+
vector<int> A(N);
55+
for (auto &a : A) cin >> a;
56+
57+
vector<int> U(N - 1), V(N - 1), B(N - 1), C(N - 1);
58+
vector<vector<int>> to(N);
59+
60+
for (int e = 0; e < N - 1; ++e) {
61+
cin >> U.at(e) >> V.at(e) >> B.at(e) >> C.at(e);
62+
to.at(U.at(e)).push_back(V.at(e));
63+
to.at(V.at(e)).push_back(U.at(e));
64+
}
65+
66+
const static_toptree_structure stts(to, 0);
67+
68+
vector<mint> parB(N, 1);
69+
vector<mint> parC(N, 0);
70+
71+
for (int e = 0; e < N - 1; ++e) {
72+
int u = U.at(e), v = V.at(e);
73+
if (stts.par.at(u) != v) swap(u, v);
74+
75+
assert(stts.par.at(u) == v);
76+
77+
parB.at(u) = B.at(e);
78+
parC.at(u) = C.at(e);
79+
}
80+
81+
tree_dp dp{A, parB, parC};
82+
83+
static_toptree tree(stts, dp);
84+
85+
while (Q--) {
86+
int tp;
87+
cin >> tp;
88+
if (tp == 0) {
89+
int w, x;
90+
cin >> w >> x;
91+
dp.A.at(w) = x;
92+
tree.set(w);
93+
} else {
94+
int e, y, z;
95+
cin >> e >> y >> z;
96+
97+
int u = U.at(e), v = V.at(e);
98+
if (stts.par.at(u) != v) swap(u, v);
99+
assert(stts.par.at(u) == v);
100+
101+
dp.parB.at(u) = y;
102+
dp.parC.at(u) = z;
103+
tree.set(u);
104+
}
105+
106+
cout << tree.all_prod().sum.val() << '\n';
107+
}
108+
}

0 commit comments

Comments
 (0)