[洛谷P3178][HAOI2015]树上操作
题目大意:有一棵点数为 $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\n", 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\n", 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;
}

浙公网安备 33010602011771号