noip模拟赛 三部曲
分析:子树上操作,要用到线段树+dfs序,关键就是子树内k还要增加,这个就不是很好办.可以求出在根节点+0后每个点会加多少,记为d[i],如果要对点x进行A操作,实际上只需要对子树加k - d[i]再加上子树的d[i]和,但是在实际求答案的时候不能直接求出子树和+Σd[i],因为如果你没有修改的话答案本该是0,程序却会输出一个数.因此还要维护一个线段树,记录Σd[i],每次在修改操作的时候将信息合并到第一个线段树上.还要注意的是每个点加的次数不同Σd[i]对答案是有影响的,不能单单只下传一个增加标记,还要记录当前节点增加了多少次,如果点x增加k,那么它的子节点就要增加(k - d[x]) * son[x] + Σd[son[x]] * cnt[x],son[x]为x的子节点,cnt[x]为x增加了多少次.
这道题比较麻烦,要很快反应过来这道题用dfs序+线段树来做,把每次增加变成在一个标准量上增加.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 50010; typedef long long ll; ll dfs_clock, n, p, head[maxn], to[maxn * 2],d[maxn], nextt[maxn * 2], tot = 1; ll l[maxn], r[maxn], v[maxn], c[maxn << 2], tag[maxn << 2], L[maxn << 2], R[maxn << 2], c2[maxn << 2], cnt[maxn << 2]; void add(ll x, ll y) { to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } void dfs(ll u, ll dep) { v[u] += dep; l[u] = ++dfs_clock; d[dfs_clock] = dep; for (int i = head[u]; i; i = nextt[i]) { int vv = to[i]; dfs(vv, dep + 1); v[u] += v[vv]; } r[u] = dfs_clock; } void pushup2(int o) { c2[o] = c2[o * 2] + c2[o * 2 + 1]; } void pushup(int o) { c[o] = c[o * 2] + c[o * 2 + 1]; } void pushdown(int o) { if (cnt[o]) { tag[o * 2] += tag[o]; tag[o * 2 + 1] += tag[o]; cnt[o * 2] += cnt[o]; cnt[o * 2 + 1] += cnt[o]; c[o * 2] += tag[o] * (R[o * 2] - L[o * 2] + 1) + cnt[o] * c2[o * 2]; c[o * 2 + 1] += tag[o] * (R[o * 2 + 1] - L[o * 2 + 1] + 1) + cnt[o] * c2[o * 2 + 1]; tag[o] = cnt[o] = 0; } } void build(int o, int l, int r) { L[o] = l; R[o] = r; if (l == r) { c2[o] = d[l]; return; } int mid = (l + r) >> 1; build(o * 2, l, mid); build(o * 2 + 1, mid + 1, r); pushup2(o); } void update(int o, int l, int r, int x, int y, int p) { if (x <= l && r <= y) { tag[o] += p; cnt[o]++; c[o] += p * (r - l + 1) + c2[o]; return; } pushdown(o); int mid = (l + r) >> 1; if (x <= mid) update(o * 2, l, mid, x, y, p); if (y > mid) update(o * 2 + 1, mid + 1, r, x, y, p); pushup(o); } ll query(int o, int l, int r, int x, int y) { if (x <= l && r <= y) return c[o]; pushdown(o); int mid = (l + r) >> 1, res = 0; if (x <= mid) res += query(o * 2, l, mid, x, y); if (y > mid) res += query(o * 2 + 1, mid + 1, r, x, y); return res; } int main() { scanf("%lld%lld", &n, &p); for (int i = 2; i <= n; i++) { int u; scanf("%d", &u); add(u, i); } for (int i = 1; i <= n; i++) if (!l[i]) dfs(i, 0); build(1, 1, n); while (p--) { char ch[2]; int x, k; scanf("%s", ch); if (ch[0] == 'A') { scanf("%d%d", &x, &k); k -= d[l[x]]; update(1, 1, n, l[x], r[x], k); } else { scanf("%d", &x); printf("%lld\n", query(1, 1, n, l[x], r[x])); } } return 0; }