Description
因为外来的入侵,国王决定在某些城市加派士兵。所有城市初始士兵数量为0。当城市 被加派了k名士兵时。城市i的所有子城市需要被加派k+1名士兵。这些子城市的所有子城市需要被加派k+2名士兵。以此类推。
当然,加派士兵的同时,国王也需要不断了解当前的情况。于是他随时可能询问以城市i为根的子树中的所有城市共被加派了多少士兵。
你现在是国王的军事大臣,你能回答出国王的每个询问么?
Input
第一行,包含两个整数N,P代表城市数量以及国王的命令的数量。
第二行N-1个整数,表示2->N号每个节点的父亲节点。
接下来的P行,每行代表国王的一个命令,命令分两种:
A X K 在城市X加入K个士兵
Q X询问以城市X为根的子树中所有士兵数量的和
Output
对于每个Q,输出答案
Hint
对于50%的数据,1<=n<=1000,1<=p<=300
对于100%的数据,1<=n<=50000,1<=p<=100000,1<=x<=n,0<=k<=1000
Solution
这种类型的题目一般可以树链剖分直接上
然鹅这里是可以dfs序+线段树直接按照点维护的,那么我们这样做就可以啦
考虑对城市i增派k,那么以i为根的子树总的贡献就是size[i]∗k+∑dep[j]−size[i]∗dep[i] 可以发现与i有关的都是可以提前求的常数
Code
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <queue>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define erg(i, st) for (int i = ls[st]; i; i = e[i].next)
#define fill(x, t) memset(x, t, sizeof(x))
#define max(x, y) ((x)>(y)?(x):(y))
#define min(x, y) ((x)<(y)?(x):(y))
#define abs(x) ((x)<(0)?(-(x)):(x))
#define ll long long
#define INF 0x3f3f3f3f
#define N 60001
#define E N * 2 + 1
#define L 1001
struct treeNode {int l, r; ll c, tag1, tag2, len;} t[N << 2 | 1], s[N << 2 | 1];
struct edge {int x, y, next;} e[E];
ll size[N], dep[N], ord[N], ls[N], v[N], edgeCnt = 0;
inline int read() {
int x = 0; char ch = getchar();
for(; ch<'0'||ch>'9'; ch=getchar());
for(; ch<='9'&&ch>='0'; (x*=10)+=ch-'0',ch=getchar());
return x;
}
inline void writeln(ll x) {
char ch[L] = {};
int i = 0;
if (x < 0) putchar('-');
do{ch[++ i] = '0' + x % 10;} while (x /= 10);
while (i) putchar(ch[i --]);
putchar('\n');
}
inline void addEdge(int x, int y) {
e[++ edgeCnt] = (edge) {x, y, ls[x]}; ls[x] = edgeCnt;
}
inline void dfs(int now, int D) {
size[now] = 1;
ord[now] = ++ ord[0];
dep[ord[0]] = D;
erg(i, now) {
dfs(e[i].y, D + 1);
size[now] += size[e[i].y];
}
}
inline void pushDown(int now) {
if (!t[now].tag1 && !t[now].tag2) {
return ;
}
t[now << 1].tag1 += t[now].tag1; t[now << 1 | 1].tag1 += t[now].tag1;
t[now << 1].tag2 += t[now].tag2; t[now << 1 | 1].tag2 += t[now].tag2;
t[now << 1].c += t[now << 1].len * t[now].tag1 + s[now << 1].c * t[now].tag2;
t[now << 1 | 1].c += t[now << 1 | 1].len * t[now].tag1 + s[now << 1 | 1].c * t[now].tag2;
t[now].tag1 = t[now].tag2 = 0;
}
inline void modify(int now, int l, int r, int v) {
if (t[now].l == l && t[now].r == r) {
t[now].tag1 += v;
t[now].tag2 += 1;
t[now].c += t[now].len * v + s[now].c;
return ;
} else {
int mid = (t[now].l + t[now].r) >> 1;
pushDown(now);
if (r <= mid) {
modify(now << 1, l, r, v);
} else if (l > mid) {
modify(now << 1 | 1, l, r, v);
} else {
modify(now << 1, l, mid, v);
modify(now << 1 | 1, mid + 1, r, v);
}
t[now].c = t[now << 1].c + t[now << 1 | 1].c;
}
}
inline ll query(int now, int l, int r) {
if (t[now].l == l && t[now].r == r) {
return t[now].c;
} else {
pushDown(now);
int mid = (t[now].l + t[now].r) >> 1;
if (r <= mid) {
return query(now << 1, l, r);
} else if (l > mid) {
return query(now << 1 | 1, l, r);
} else {
return query(now << 1, l, mid) + query(now << 1 | 1, mid + 1, r);
}
}
}
inline void buildTree(int now, int l, int r) {
int mid = (l + r) >> 1;
t[now] = (treeNode) {l, r, 0, 0, 0, r - l + 1};
s[now] = (treeNode) {l, r, 0, 0, 0, r - l + 1};
if (l == r) {
s[now].c = dep[l];
return ;
}
buildTree(now << 1, l, mid);
buildTree(now << 1 | 1, mid + 1, r);
s[now].c = s[now << 1].c + s[now << 1 | 1].c;
}
int main(void) {
ll n = read();
ll m = read();
rep(i, 2, n) {
addEdge(read(), i);
}
dfs(1, 0);
buildTree(1, 1, ord[0]);
rep(i, 1, m + 1) {
char opt = getchar();
if (opt == 'A') {
int x = read();
int y = read();
modify(1, ord[x], ord[x] + size[x] - 1, y - dep[ord[x]]);
} else if (opt == 'Q') {
int x = read();
ll prt = query(1, ord[x], ord[x] + size[x] - 1);
writeln(prt);
}
}
return 0;
}

366

被折叠的 条评论
为什么被折叠?



