【线段树】E. Danil and a Part-time Job(dfs序+线段树)
题意:
一棵树每个节点的权值只有0和1
1.get x表示求x的子树权值和
2. pow x表示把x及的子树^1
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+5;
int n, q,cnt,dfn[maxn],low[maxn],id[maxn];
int val[maxn], lazy[200009 << 2], sum[200009 << 2];
vector<int>mp[maxn];
void pushdown(int k,int lsum,int rsum){
if(lazy[k]){
sum[k<<1]=lsum-sum[k<<1];
sum[k<<1|1]=rsum-sum[k<<1|1];
lazy[k<<1]^=1;
lazy[k<<1|1]^=1;
lazy[k]=0;
}
}
void build(int k, int l, int r){
if (l == r){
sum[k] = val[id[l]];
return;
}
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
sum[k] = sum[k << 1] + sum[k << 1 | 1];
}
void update(int k, int l, int r, int ll, int rr){
if (l >= ll && r <= rr ) {
sum[k] = r-l+1-sum[k];
lazy[k]^=1;
return;
}
int mid = (l + r) >> 1;
pushdown(k,mid-l+1,r-mid);
if (ll <= mid) update(k << 1, l, mid, ll, rr);
if (rr > mid) update(k << 1 | 1, mid + 1, r, ll, rr);
sum[k] = sum[k << 1] + sum[k << 1 | 1];
}
int query(int k, int l, int r, int ll, int rr){
if (l >= ll && r <= rr) return sum[k];
int mid = (l + r) >> 1;
int ans = 0;
pushdown(k,mid-l+1,r-mid);
if (ll <= mid) ans += query(k << 1, l, mid, ll, rr);
if (rr > mid) ans += query(k << 1 | 1, mid + 1, r, ll, rr);
return ans;
}
void dfs(int x){
dfn[x]=++cnt;
id[cnt]=x;
for(auto y:mp[x])dfs(y);
low[x]=cnt;
}
int main(){
scanf("%d",&n);
for(int i=2,x;i<=n;i++){
scanf("%d",&x);
mp[x].push_back(i);
}
for(int i=1;i<=n;i++)
scanf("%d",&val[i]);
dfs(1);
build(1, 1, n);
scanf("%d",&q);
while (q--){
char p[12];
int x;
scanf("%s%d",p,&x);
if (p[0] == 'p') update(1, 1, n, dfn[x], low[x]);
else printf("%d\n", query(1, 1, n, dfn[x], low[x]));
}
}