题目大意:有一棵点数为 $N$ 的树,以点 1 为根。然后有 $M$ 个操作。
1. 把 $x$ 的点权增加 $a$ 。
2. 把 $x$ 为根的子树中所有点的点权都增加 $a$ 。
3. 询问 $x$ 到根的路径中所有点的点权和。
题解:树链剖分模板题
卡点:我真的好久没打树剖了。。。
1.线段树$tag$写错
2.树剖$query$打错
3.一堆东西没开$long ; long$
C++ Code:
#include <cstdio> #define maxn 100010 using namespace std; int n, m, S[maxn], s[maxn]; int head[maxn], cnt; struct Edge { int to, nxt; } e[maxn << 1]; void add(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; } int dfn[maxn], son[maxn], sz[maxn], idx; int dep[maxn], fa[maxn], top[maxn]; void dfs1(int rt) { sz[rt] = 1; for (int i = head[rt]; i; i = e[i].nxt) { int v = e[i].to; if (v != fa[rt]) { dep[v] = dep[rt] + 1; fa[v] = rt; dfs1(v); if (!son[rt] || sz[v] > sz[son[rt]]) son[rt] = v; sz[rt] += sz[v]; } } } void dfs2(int rt) { dfn[rt] = ++idx; int v = son[rt]; if (v) top[v] = top[rt], dfs2(v); for (int i = head[rt]; i; i = e[i].nxt) { v = e[i].to; if (v != fa[rt] && v != son[rt]) { top[v] = v; dfs2(v); } } } long long v[maxn << 2], cov[maxn << 2]; void build(int rt, int l, int r) { if (l == r) { v[rt] = s[l]; return ; } int mid = l + r >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); v[rt] = v[rt << 1] + v[rt << 1 | 1]; } void pushdown(int rt, int len) { long long &tmp = cov[rt]; v[rt << 1] += tmp * (len + 1 >> 1); v[rt << 1 | 1] += tmp * (len >> 1); cov[rt << 1] += tmp; cov[rt << 1 | 1] += tmp; tmp = 0; } void add(int rt, int l, int r, int L, int R, long long num) { if (L <= l && R >= r) { v[rt] += num * (r - l + 1); cov[rt] += num; return ; } int mid = l + r >> 1; if (cov[rt]) pushdown(rt, r - l + 1); if (L <= mid) add(rt << 1, l, mid, L, R, num); if (R > mid) add(rt << 1 | 1, mid + 1, r, L, R, num); v[rt] = v[rt << 1] + v[rt << 1 | 1]; } long long ask(int rt, int l, int r, int L, int R) { if (L <= l && R >= r) { return v[rt]; } int mid = l + r >> 1; long long ans = 0; // printf("%d %d %d %d %d ", rt, l, r, L, R); if (cov[rt]) pushdown(rt, r - l + 1); if (L <= mid) ans = ask(rt << 1, l, mid, L, R); if (R > mid) ans += ask(rt << 1 | 1, mid + 1, r, L, R); return ans; } long long query(int rt) { long long ans = 0; while (top[rt] != 1) { ans += ask(1, 1, n, dfn[top[rt]], dfn[rt]); rt = fa[top[rt]]; } ans += ask(1, 1, n, dfn[1], dfn[rt]); return ans; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &S[i]); for (int i = 1; i < n; i++) { int a, b; scanf("%d%d", &a, &b); add(a, b); add(b, a); } dep[top[1] = 1] = 1; dfs1(1); dfs2(1); for (int i = 1; i <= n; i++) s[dfn[i]] = S[i]; build(1, 1, n); int op, a; long long x; while (m--) { scanf("%d%d", &op, &a); if (op == 3) { printf("%lld ", query(a)); } else { scanf("%lld", &x); if (op == 1) add(1, 1, n, dfn[a], dfn[a], x); else add(1, 1, n, dfn[a], dfn[a] + sz[a] - 1, x); } } return 0; }