#include <bits/stdc++.h>
using namespace std;
#define maxn 200005
int c[maxn * 4], lazy[maxn * 4], lft[maxn], rght[maxn], tot, sz[maxn];
vector<vector<int> > g(maxn);
void pushdown(int o, int l, int r){
if(l == r || lazy[o] == 0) return;
int mid = l + r >> 1;
c[o << 1] = mid - l + 1 - c[o << 1];
c[o << 1 | 1] = r - mid - c[o << 1 | 1];
lazy[o << 1] ^= 1;
lazy[o << 1 | 1] ^= 1;
lazy[o] = 0;
}
void add(int o, int l, int r, int L, int R){
pushdown(o, l, r);
if(l >= L && r <= R){
c[o] = r - l + 1 - c[o];
lazy[o] ^= 1;
return ;
}
int mid = l + r >> 1;
if(mid >= L) add(o << 1, l, mid, L, R);
if(mid < R) add(o << 1 | 1, mid + 1, r, L, R);
c[o] = c[o << 1] + c[o << 1 | 1];
}
void dfs(int x){
lft[x] = tot;
for(int i = 0; i < g[x].size(); ++i){
tot++;
dfs(g[x][i]);
}
rght[x] = tot;
}
int getsum(int o, int l, int r, int L, int R){
pushdown(o, l, r);
if(l >= L && r <= R){
return c[o];
}
int mid = l + r >> 1;
int ans = 0;
if(mid >= L) ans += getsum(o << 1, l, mid, L, R);
if(mid < R) ans += getsum(o << 1 | 1, mid + 1, r, L, R);
return ans;
}
int main(){
int n, q, u;
cin>>n;
for(int i = 2; i <= n; ++i){
scanf("%d", &u);
g[u].push_back(i);
}
memset(c, 0, sizeof(c));
memset(lazy, 0, sizeof(lazy));
for(int i = 1; i <= n; ++i){
scanf("%d", &sz[i]);
}
tot = 1;
dfs(1);
for(int i = 1; i <= n; ++i){
if(sz[i]) add(1, 1, n, lft[i], lft[i]);
}
char s[5];
scanf("%d", &q);
while(q--){
scanf("%s", s);
if(s[0] == 'p'){
scanf("%d", &u);
add(1, 1, n, lft[u], rght[u]);
sz[u] ^= 1;
}
else{
scanf("%d", &u);
printf("%d\n", getsum(1, 1, n, lft[u], rght[u]));
}
}
}
/*
题意:一棵树,2e5个节点,每个节点上一个灯泡,2e5次操作,每次操作要么将以某个节点为子树上的所有灯泡
全部翻转(开变关,关变开),要么询问以某个节点为子树上有多少个灯泡是亮的。
思路:
裸的dfs树形转线性+线段树区间修改和查询。。。。这题搞个dfs序就行了,维护一下子树上最小编号和最大编号,然后对应到线性区间上。
区间修改和查询应该是线段树的基本操作了,用lazy记下翻转标记,
*/
Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job (dfs序树型转线性 线段树区间修改区间查询)
最新推荐文章于 2020-09-01 20:16:49 发布