题意:给出一棵树,做 M 次操作,每次要么将一棵子树上每个结点的布尔值取反,要么查询一棵子树上布尔值为 true 的个数
思路:先 dfs 将树转化成一个序列,然后用线段树维护,区间修改/区间查询
#include <iostream>
#include <vector>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 100005;
vector <int> g[maxn];
int id,len[maxn<<2],cnt[maxn<<2],mark[maxn<<2];
struct node
{
int l,r;
}point[maxn];
void dfs(int cur)
{
point[cur].l=++id;
for(int i=0;i<g[cur].size();++i)
dfs(g[cur][i]);
point[cur].r = id;
}
void build(int l,int r,int rt)
{
cnt[rt]=0;
mark[rt]=0;
len[rt]=r-l+1;
if(l==r) return;
int m=(l+r)>>1;
build(lson);
build(rson);
}
void push_up(int rt)
{
cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1];
}
void push_down(int rt)
{
if(mark[rt])
{
cnt[rt<<1]=len[rt<<1]-cnt[rt<<1];
mark[rt<<1]^=1;
cnt[rt<<1|1]=len[rt<<1|1]-cnt[rt<<1|1];
mark[rt<<1|1]^=1;
mark[rt]=0;
}
}
void update(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
cnt[rt]=len[rt]-cnt[rt];
if(l==r) return;
mark[rt]^=1;
return;
}
push_down(rt);
int m=(l+r)>>1;
if(L<=m) update(L,R,lson);
if(R>m) update(L,R,rson);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt)
{
int ans=0;
if(L<=l&&R>=r)
{
return cnt[rt];
}
push_down(rt);
int m=(l+r)>>1;
if(L<=m) ans+=query(L,R,lson);
if(R>m) ans+=query(L,R,rson);
return ans;
}
int main()
{
int n,m,t,k;
char s;
while (cin>>n>>m)
{
for(int i=1;i<=n;++i) g[i].clear();
for(int i=2;i<=n;++i)
{
cin>>t;
g[t].push_back(i);
}
id=0;
dfs(1);
build(1,n,1);
while(m--)
{
cin>>s>>k;
//cout<<point[k].l<<' '<<point[k].r<<endl;
if(s=='o') update(point[k].l,point[k].r,1,n,1);
else cout<<query(point[k].l,point[k].r,1,n,1)<<endl;
}
cout<<endl;
}
return 0;
}