From 38fd50cc64d3e2fa001e40bea57a6e4dcc08cb9c Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Fri, 17 Dec 2021 20:36:04 +0800 Subject: [PATCH] =?UTF-8?q?P3384=20=E3=80=90=E6=A8=A1=E6=9D=BF=E3=80=91?= =?UTF-8?q?=E8=BD=BB=E9=87=8D=E9=93=BE=E5=89=96=E5=88=86/=E6=A0=91?= =?UTF-8?q?=E9=93=BE=E5=89=96=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R65189455 --- Luogu/P3384/P3384.cpp | 220 +++++++++++++++++++---------------- Luogu/P3384/data/P3384_2.in | 3 + Luogu/P3384/data/P3384_2.out | 3 + 3 files changed, 127 insertions(+), 99 deletions(-) create mode 100644 Luogu/P3384/data/P3384_2.in create mode 100644 Luogu/P3384/data/P3384_2.out diff --git a/Luogu/P3384/P3384.cpp b/Luogu/P3384/P3384.cpp index 1f7731a2..6858b245 100644 --- a/Luogu/P3384/P3384.cpp +++ b/Luogu/P3384/P3384.cpp @@ -1,10 +1,63 @@ -#include +#include +#include -using namespace std; +using std::cin; +using std::cout; +using std::endl; -int n, m, r, p, a[100005], x, y, op, u, v, k; -vector g[100005]; -int cnt, dep[100005], fa[100005], siz[100005], son[100005], id[100005], top[100005], w[100005]; +const int N = 100005; + +int p, a[N]; +std::vector g[N]; + +// Segment Tree +void build(int, int, int); + +// Heavy Path Decomposition +int cnt, id[N], rid[N], fa[N], dep[N], siz[N], son[N], top[N]; +void dfs1(int, int); +void dfs2(int, int); +void modify_path(int, int, int); +void modify_tree(int, int); +long long query_path(int, int); +long long query_tree(int); + +int main() { + int n, m, r; + cin >> n >> m >> r >> p; + for (int i = 1; i <= n; i++) { + cin >> a[i]; + } + for (int i = 1; i < n; i++) { + int x, y; + cin >> x >> y; + g[x].push_back(y); + g[y].push_back(x); + } + dfs1(r, r); + dfs2(r, r); + build(1, 1, n); + while (m--) { + int op, x, y, z; + cin >> op; + if (op == 1) { + cin >> x >> y >> z; + modify_path(x, y, z); + } else if (op == 2) { + cin >> x >> y; + cout << query_path(x, y) << endl; + } else if (op == 3) { + cin >> x >> z; + modify_tree(x, z); + } else { + cin >> x; + cout << query_tree(x) << endl; + } + } + return 0; +} + +// === Segment Tree === struct node { int l, r; @@ -14,11 +67,61 @@ struct node { : l(0), r(0), s(0), d(0) {} node(int _l, int _r) : l(_l), r(_r), s(0), d(0) {} -} tr[100005 << 2]; +} tr[N << 2]; + +inline void pushup(int u) { + tr[u].s = (tr[u << 1].s + tr[u << 1 | 1].s) % p; +} + +inline void pushdown(int u) { + node &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1]; + left.s = (left.s + (left.r - left.l + 1) * root.d) % p; + left.d = (left.d + root.d) % p; + right.s = (right.s + (right.r - right.l + 1) * root.d) % p; + right.d = (right.d + root.d) % p; + root.d = 0; +} + +void build(int u, int l, int r) { + tr[u] = node(l, r); + if (l == r) { + tr[u].s = a[rid[l]] % p; + return; + } + int mid = l + r >> 1; + build(u << 1, l, mid); + build(u << 1 | 1, mid + 1, r); + pushup(u); +} + +void modify(int u, int l, int r, int d) { + if (l <= tr[u].l && tr[u].r <= r) { + tr[u].s = (tr[u].s + (tr[u].r - tr[u].l + 1) * d) % p; + tr[u].d = (tr[u].d + d) % p; + return; + } + pushdown(u); + int mid = tr[u].l + tr[u].r >> 1; + if (l <= mid) modify(u << 1, l, r, d); + if (r > mid) modify(u << 1 | 1, l, r, d); + pushup(u); +} + +long long query(int u, int l, int r) { + if (l <= tr[u].l && tr[u].r <= r) return tr[u].s % p; + pushdown(u); + int mid = tr[u].l + tr[u].r >> 1; + long long res = 0; + if (l <= mid) res = (res + query(u << 1, l, r)) % p; + if (r > mid) res = (res + query(u << 1 | 1, l, r)) % p; + return res; +} + +// == Heavy Path Decomposition === void dfs1(int u, int f) { - dep[u] = dep[f] + 1; fa[u] = f; + dep[u] = dep[f] + 1; siz[u] = 1; for (int v : g[u]) { if (v == f) continue; @@ -30,7 +133,7 @@ void dfs1(int u, int f) { void dfs2(int u, int t) { id[u] = ++cnt; - w[cnt] = a[u]; + rid[id[u]] = u; top[u] = t; if (!son[u]) return; dfs2(son[u], t); @@ -41,113 +144,32 @@ void dfs2(int u, int t) { } } -void pushup(int u) { - tr[u].s = (tr[u << 1].s + tr[u << 1 | 1].s) % p; -} - -void pushdown(int u) { - if (!tr[u].d) return; - tr[u << 1].s = (tr[u << 1].s + (tr[u << 1].r - tr[u << 1].l + 1) * tr[u].d) % p; - tr[u << 1].d = (tr[u << 1].d + tr[u].d) % p; - tr[u << 1 | 1].s = (tr[u << 1 | 1].s + (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) * tr[u].d) % p; - tr[u << 1 | 1].d = (tr[u << 1 | 1].d + tr[u].d) % p; - tr[u].d = 0; -} - -void build(int u, int l, int r) { - tr[u] = node(l, r); - if (l == r) { - tr[u].s = w[r]; - return; - } - int mid = l + r >> 1; - build(u << 1, l, mid); - build(u << 1 | 1, mid + 1, r); - pushup(u); -} - -void modify(int u, int l, int r, int k) { - if (l <= tr[u].l && tr[u].r <= r) { - tr[u].s = (tr[u].s + (tr[u].r - tr[u].l + 1) * k) % p; - tr[u].d = (tr[u].d + k) % p; - return; - } - int mid = tr[u].l + tr[u].r >> 1; - pushdown(u); - if (l <= mid) modify(u << 1, l, r, k); - if (r > mid) modify(u << 1 | 1, l, r, k); - pushup(u); -} - -long long query(int u, int l, int r) { - if (l <= tr[u].l && tr[u].r <= r) { - return tr[u].s % p; - } - int mid = tr[u].l + tr[u].r >> 1; - long long sum = 0; - pushdown(u); - if (l <= mid) sum = (sum + query(u << 1, l, r)) % p; - if (r > mid) sum = (sum + query(u << 1 | 1, l, r)) % p; - return sum; -} - -void modify_path(int u, int v, int k) { +void modify_path(int u, int v, int d) { while (top[u] != top[v]) { - if (dep[top[u]] < dep[top[v]]) swap(u, v); - modify(1, id[top[u]], id[u], k); + if (dep[top[u]] < dep[top[v]]) std::swap(u, v); + modify(1, id[top[u]], id[u], d); u = fa[top[u]]; } - if (dep[u] < dep[v]) swap(u, v); - modify(1, id[v], id[u], k); + if (dep[u] < dep[v]) std::swap(u, v); + modify(1, id[v], id[u], d); } long long query_path(int u, int v) { long long sum = 0; while (top[u] != top[v]) { - if (dep[top[u]] < dep[top[v]]) swap(u, v); + if (dep[top[u]] < dep[top[v]]) std::swap(u, v); sum = (sum + query(1, id[top[u]], id[u])) % p; u = fa[top[u]]; } - if (dep[u] < dep[v]) swap(u, v); + if (dep[u] < dep[v]) std::swap(u, v); sum = (sum + query(1, id[v], id[u])) % p; return sum; } -void modify_tree(int u, int k) { - modify(1, id[u], id[u] + siz[u] - 1, k); +inline void modify_tree(int u, int d) { + modify(1, id[u], id[u] + siz[u] - 1, d); } -long long query_tree(int u) { +inline long long query_tree(int u) { return query(1, id[u], id[u] + siz[u] - 1); } - -int main() { - cin >> n >> m >> r >> p; - for (int i = 1; i <= n; i++) { - cin >> a[i]; - } - for (int i = 1; i < n; i++) { - cin >> x >> y; - g[x].push_back(y); - g[y].push_back(x); - } - dfs1(r, 0); - dfs2(r, r); - build(1, 1, n); - for (int i = 1; i <= m; i++) { - cin >> op >> u; - if (op == 1) { - cin >> v >> k; - modify_path(u, v, k); - } else if (op == 2) { - cin >> v; - cout << query_path(u, v) % p << endl; - } else if (op == 3) { - cin >> k; - modify_tree(u, k); - } else { - cout << query_tree(u) % p << endl; - } - } - return 0; -} diff --git a/Luogu/P3384/data/P3384_2.in b/Luogu/P3384/data/P3384_2.in new file mode 100644 index 00000000..262c5a6f --- /dev/null +++ b/Luogu/P3384/data/P3384_2.in @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:76e51d37fd9cf91ac85b82308e00b34c2a368f6e4b9dea4e7a2c0af67ba12dfc +size 2840884 diff --git a/Luogu/P3384/data/P3384_2.out b/Luogu/P3384/data/P3384_2.out new file mode 100644 index 00000000..9b479c65 --- /dev/null +++ b/Luogu/P3384/data/P3384_2.out @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb7f2448c7c3ebc5523d483294ac862b05ca51f98acc540afe85bd4b4f0c5bb3 +size 333952