[codeforces] 877E. Danil and a Part-time Job(DFS序+线段树)
题目链接: E. Danil and a Part-time Job
题目大意:
给一棵大小为n的以1为根节点的树。 每个点的值为0或1, 有q个操作:
1. pow v, 对于v以及v的子树所有节点01反转。
2. get v, 查询v以及v的子树中1节点的个数。
数据范围:
解题思路:
dfs序+线段树, 线段树用来维护每个点被反转了几次, 通过这道题让我又深一步的理解了线段树下放的思想: 当你查询到一个点的时候, 这个点肯定已经是被操作过的。所以反转应该写在下放的时候。
AC代码:
/********************************************
*Author* :ZZZZone
*Created Time* : 五 11/ 3 20:03:46 2017
* Ended Time* : 六 11/ 4 00:05:58 2017
*********************************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;
const int MaxN = 2e5;
vector<int> edge[MaxN + 5];
int head[MaxN + 5], tail[MaxN + 5], re[MaxN + 5];
int n, q, tot, now;
int a[MaxN + 5];
int sum1[4 * MaxN + 5], sum0[4 * MaxN + 5], add[4 * MaxN + 5];
void dfs(int u, int fa){
head[u] = ++tot;
re[tot] = u;
for(int i = 0; i < edge[u].size(); i++){
int v = edge[u][i];
if(v != fa) dfs(v, u);
}
tail[u] = tot;
}
void pushup(int rt){
sum1[rt] = sum1[rt << 1] + sum1[rt << 1 | 1];
sum0[rt] = sum0[rt << 1] + sum0[rt << 1 | 1];
}
void build(int l, int r, int rt){
if(l == r){
now++;
if(a[re[now]] == 1) sum1[rt]++;
else sum0[rt]++;
return;
}
int mid = (l + r) >> 1;
build(l, mid, rt << 1);
build(mid + 1, r, rt << 1 | 1);
pushup(rt);
}
void pushdown(int rt){
if(add[rt]){
add[rt << 1] ^= 1;
add[rt << 1 | 1] ^= 1;
swap(sum1[rt << 1], sum0[rt << 1]);
swap(sum1[rt << 1 | 1], sum0[rt << 1 | 1]);
add[rt] = 0;
}
}
void update(int L, int R, int l, int r, int rt){
if(L <= l && R >= r){
swap(sum0[rt], sum1[rt]);
add[rt] ^= 1;
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if(L <= mid) update(L, R, l, mid, rt << 1);
if(R > mid) update(L, R, mid + 1, r, rt << 1 | 1);
pushup(rt);
}
int query(int L, int R, int l, int r, int rt){
if(L <= l && R >= r){
//printf("%d %d %d ", sum0[rt], sum1[rt], add[rt]);
return sum1[rt];
}
pushdown(rt);
int mid = (r + l) >> 1;
LL ret = 0;
if(L <= mid) ret += query(L, R, l, mid, rt << 1);
if(R > mid) ret += query(L, R, mid + 1, r, rt << 1 | 1);
return ret;
}
int main()
{
scanf("%d", &n);
for(int i = 2; i <= n; i++){
int u;
scanf("%d", &u);
edge[u].push_back(i);
}
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
dfs(1, 0);
scanf("%d", &q);
build(1, n, 1);
while(q--){
char tmp[5];
int p;
scanf("%s %d\n", tmp, &p);
if(tmp[0] == 'p') update(head[p], tail[p], 1, n, 1);
else if(tmp[0] == 'g') printf("%d\n", query(head[p], tail[p], 1, n, 1));
}
return 0;
}