模板树链剖分
Posted blog-fgy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板树链剖分相关的知识,希望对你有一定的参考价值。
题目链接:https://loj.ac/problem/139
#include <iostream> #include <cstdio> #define LL long long #define Re register #define min(a, b) (a < b ? a : b) #define max(a, b) (a > b ? a : b) #define maxN 100005 inline LL read() { LL x = 0, f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == ‘-‘) f = -1; ch = getchar(); } while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar(); return x * f; } using namespace std; LL Ans; struct Segment_Tree { int l, r, tag; LL sum; #define ls (rt << 1) #define rs (rt << 1 | 1) } t[maxN << 2]; struct Edge { int nxt, to; } e[maxN << 1]; int cnte = 1, head[maxN]; inline void add_Edge(int i, int j) { e[++cnte].nxt = head[i], e[cnte].to = j, head[i] = cnte; } int N, val[maxN], M, root, tot, siz[maxN], hson[maxN], top[maxN], num[maxN], dfn[maxN], dep[maxN], fa[maxN]; void dfs1(int u, int FA) { fa[u] = FA, siz[u] = 1, dep[u] = dep[FA] + 1; for (int v, i = head[u]; i; i = e[i].nxt) { if ((v = e[i].to) == FA) continue; dfs1(v, u), siz[u] += siz[v]; if (siz[v] > siz[hson[u]]) hson[u] = v; } } void dfs2(int u, int TOP) { dfn[u] = ++tot, num[dfn[u]] = u, top[u] = TOP; if (!hson[u]) return; dfs2(hson[u], TOP); for (Re int i = head[u]; i; i = e[i].nxt) { Re int v = e[i].to; if (v != fa[u] && v != hson[u]) dfs2(v, v); } } inline void pushup(int rt) { t[rt].sum = t[ls].sum + t[rs].sum; } inline void pushdown(int rt) { if (!t[rt].tag) return; t[ls].sum += (t[ls].r - t[ls].l + 1) * t[rt].tag; t[rs].sum += (t[rs].r - t[rs].l + 1) * t[rt].tag; t[ls].tag += t[rt].tag, t[rs].tag += t[rt].tag; t[rt].tag = 0; } void Build_Tree(int rt, int l, int r) { t[rt].l = l, t[rt].r = r; if (l == r) { t[rt].sum = val[num[l]]; return; } int mid = (l + r) >> 1; Build_Tree(ls, l, mid), Build_Tree(rs, mid + 1, r); pushup(rt); } void update(int rt, int l, int r, int c) { if (l <= t[rt].l && t[rt].r <= r) { t[rt].tag += c; t[rt].sum += (t[rt].r - t[rt].l + 1) * c; return; } pushdown(rt); int mid = (t[rt].l + t[rt].r) >> 1; if (l <= mid) update(ls, l, r, c); if (mid < r) update(rs, l, r, c); pushup(rt); } LL query(int rt, int l, int r) { if (l <= t[rt].l && t[rt].r <= r) return t[rt].sum; pushdown(rt); int mid = (t[rt].l + t[rt].r) >> 1; LL ret = 0; if (l <= mid) ret += query(ls, l, r); if (mid < r) ret += query(rs, l, r); return ret; } void update_path(int x, int y, int k) { while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) x ^= y ^= x ^= y; update(1, dfn[top[x]], dfn[x], k); x = fa[top[x]]; } update(1, min(dfn[x], dfn[y]), max(dfn[x], dfn[y]), k); } void Q_path(int x, int y) { Ans = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) x ^= y ^= x ^= y; Ans += query(1, dfn[top[x]], dfn[x]); x = fa[top[x]]; } Ans += query(1, min(dfn[x], dfn[y]), max(dfn[x], dfn[y])); } int LCA(int x, int y) { while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) x ^= y ^= x ^= y; x = fa[top[x]]; } return dep[x] < dep[y] ? x : y; } int find(int x, int y) { while (top[x] != top[y]) { if (fa[top[y]] == x) return top[y]; y = fa[top[y]]; } return hson[x]; } void Q_tree(int u) { if (LCA(root, u) != u) Ans = query(1, dfn[u], dfn[u] + siz[u] - 1); else if (u == root) Ans = t[1].sum; else { int s = find(u, root); Ans = t[1].sum - query(1, dfn[s], dfn[s] + siz[s] - 1); } } void update_tree(int u, int k) { if (LCA(root, u) != u) update(1, dfn[u], dfn[u] + siz[u] - 1, k); else if (root == u) update(1, 1, tot, k); else { int s = find(u, root); update(1, 1, tot, k); update(1, dfn[s], dfn[s] + siz[s] - 1, -k); } } int main() { N = read(); for (Re int i = 1; i <= N; ++i) val[i] = read(); for (Re int i = 2; i <= N; ++i) { Re int x = read(); add_Edge(i, x), add_Edge(x, i); } dfs1(1, 0), dfs2(1, 1); Build_Tree(1, 1, tot); M = read(); while (M--) { int u, v, k; int opt = read(); if (opt == 1) root = read(); if (opt == 2) { u = read(), v = read(), k = read(); update_path(u, v, k); } if (opt == 3) { u = read(), k = read(); update_tree(u, k); } if (opt == 4) { u = read(), v = read(); Q_path(u, v); printf("%lld ", Ans); } if (opt == 5) { u = read(); Q_tree(u); printf("%lld ", Ans); } } return 0; }
以上是关于模板树链剖分的主要内容,如果未能解决你的问题,请参考以下文章