14113: 【原4113】Seven Apples 0n a Witch’s Tree
题目
题目描述
author: 黄俊翔 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/4113 ## Description
历经无数周折后,赫萝与罗伦斯最终在纽希拉安定下来,并开了一家温泉旅馆。为了让年幼的女儿缪莉时刻有苹果吃,赫萝在旅馆旁种了一棵苹果树。
这棵树具有魔法,因此它满足以下这样一些性质:它真的长成一棵树(数据结构意义上)的形状,并在每个节点上都长了且最多只长一个苹果,包括编号为1的根节点也是。赫萝时不时会从树上摘下一个苹果,而这颗树也时不时会从空的节点上长出一个苹果。
为了统计苹果的长势(翻译:嘴馋),缪莉有时会想要知道某一颗子树上总共有多少苹果。但这棵树有些巨大,年幼的缪莉有点数不过来,你能帮帮她吗?
Input Format
第一行包含一个正整数\(N\),为苹果树的节点数。
接下来的\(N-1\)行,每行有两个正整数\(u,v\),代表编号为\(v\)的节点的父亲是\(u\)节点。
接下来的一行包含一个正整数\(M\),为接下来发生的事件数。
接下来\(M\)行,每行的内容可能是以下两种情况之一:
“\(C\ x\)”代表编号为\(x\)的节点上的苹果数量发生了变化。由于每个节点上最多只会长一个苹果,因此如果原来这个节点上有苹果,那这条信息就代表赫萝摘掉了这个苹果;如果原来这个节点上没有苹果,那这条信息就代表这个节点上长出了一个苹果。
“\(Q\ x\)”代表缪莉想要知道以节点\(x\)为根的子树上总共有多少个苹果。
Output Format
对于每个缪莉的询问输出一行,每行一个数字\(x\)代表问题的答案。
Sample Input
4
1 2
1 3
1 4
3
Q 1
C 2
Q 1
Sample Output
4
3
Data Range
对于\(30\%\)的数据,\(N,M \le 1000\),。
对于另外\(30\%\)的数据,这颗苹果树是一颗完全二叉树。(满二叉树是完全二叉树的一种,区别在于完全二叉树是指仅最后一排可能非满,且最后一排的所有节点都靠到了最左;而满二叉树的最后一排也必然是满的)
对于\(100\%\)的数据,\(N,M \le 100000\)。
FineArtz's solution
/* Seven Apples 0n a Witch's Tree */
#include <iostream>
using namespace std;
const int MAXN = 100000;
int head[MAXN + 5], nxt[MAXN + 5], e[MAXN + 5], cnt = 0;
bool b[MAXN + 5] = {false};
int n, m, root = 0;
int in[MAXN + 5], out[MAXN + 5], seq[MAXN + 5], t = 0;
bool apple[MAXN + 5] = {false};
struct Node{
int l = 0, r = 0, sum = 0;
};
Node a[MAXN * 4 + 5];
void addEdge(int u, int v){
++cnt;
nxt[cnt] = head[u];
e[cnt] = v;
head[u] = cnt;
}
void dfs(int x){
in[x] = t;
seq[t] = x;
for (int i = head[x]; i != 0; i = nxt[i]){
++t;
dfs(e[i]);
}
out[x] = t;
}
void buildTree(int x, int l, int r){
a[x].l = l;
a[x].r = r;
if (l == r){
a[x].sum = 1;
return;
}
int mid = (l + r) / 2;
buildTree(x * 2, l, mid);
buildTree(x * 2 + 1, mid + 1, r);
a[x].sum = a[x * 2].sum + a[x * 2 + 1].sum;
};
void update(int x, int p, int d){
if (a[x].l == a[x].r){
a[x].sum += d;
return;
}
int mid = (a[x].l + a[x].r) / 2;
if (p <= mid)
update(x * 2, p, d);
else
update(x * 2 + 1, p, d);
a[x].sum = a[x * 2].sum + a[x * 2 + 1].sum;
}
int query(int x, int l, int r){
if (a[x].l >= l && a[x].r <= r)
return a[x].sum;
int mid = (a[x].l + a[x].r) / 2;
int ret = 0;
if (mid >= l)
ret += query(x * 2, l, r);
if (mid < r)
ret += query(x * 2 + 1, l, r);
return ret;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i < n; ++i){
int u, v;
cin >> u >> v;
addEdge(u, v);
b[v] = true;
}
for (int i = 1; i <= n; ++i){
if (!b[i]){
root = i;
break;
}
}
t = 1;
dfs(root);
for (int i = 1; i <= n; ++i)
apple[i] = true;
buildTree(1, 1, n);
cin >> m;
while (m--){
char op;
int x;
cin >> op >> x;
if (op == 'C'){
if (apple[x]){
apple[x] = false;
update(1, in[x], -1);
}
else{
apple[x] = true;
update(1, in[x], 1);
}
}
else if (op == 'Q'){
cout << query(1, in[x], out[x]) << '\n';
}
}
return 0;
}