这次月赛太无语了。H题看起来是个全场题不知道为什么大家都被卡的蛋疼,于是就去想A题了,开始没什么想法,还以为要开N个线段树,后来WQJ说先序遍历一下就可以转换成1维线段树了,想一下确实是这样。由于不是二叉树,开始建树的时候有点蛋疼,用了数据结构讲过的儿子兄弟表示法(看来严蔚敏那本书还是有点用的)。建树之后遍历出每个节点在线段树中的对应位置和子树中节点的总数。接下来就是更新和查询的线段树操作了,一开始看错题了,还以为是每次操作都把那个子树全变成1,后来发现是反转。结果pushdown写挫了,改半天不知道哪里有问题,看了好甜的代码才改好了,伤不起,今天的状态太差了。晚上的马拉松应该又要跪了……
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define MAXN 100005
int sum[MAXN<<2];
bool lazy[MAXN<<2];
struct Node
{
int fa,son,bro;
}tree[MAXN];
int cnt,pos[MAXN],son[MAXN];
void pretravel(int k)
{
pos[k]=cnt++;
if(tree[k].son)
pretravel(tree[k].son);
if(tree[k].bro)
pretravel(tree[k].bro);
son[tree[k].fa]+=son[k]+1;
}
void pushdown(int l,int r,int rt)
{
if(lazy[rt])
{
int m=(l+r)>>1;
lazy[rt<<1]^=1;
lazy[rt<<1|1]^=1;
sum[rt<<1]=(m-l+1)-sum[rt<<1];
sum[rt<<1|1]=(r-m)-sum[rt<<1|1];
lazy[rt]=0;
}
}
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
sum[rt]=r-l+1-sum[rt];
lazy[rt]^=1;
return;
}
pushdown(l,r,rt);
int m=(l+r)>>1;
if(L<=m)
update(L,R,l,m,rt<<1);
if(R>m)
update(L,R,m+1,r,rt<<1|1);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
int res=0;
if(L<=l&&r<=R)
{
return sum[rt];
}
pushdown(l,r,rt);
int m=(l+r)>>1;
if(L<=m)
res+=query(L,R,l,m,rt<<1);
if(R>m)
res+=query(L,R,m+1,r,rt<<1|1);
pushup(rt);
return res;
}
int main()
{
// freopen("input.txt","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(tree,0,sizeof(tree));
memset(lazy,0,sizeof(lazy));
memset(sum,0,sizeof(sum));
memset(pos,0,sizeof(pos));
memset(son,0,sizeof(son));
cnt=1;
int p;
for(int i=2;i<=n;i++)
{
scanf("%d",&p);
if(tree[p].son==0)
{
tree[p].son=i;
tree[i].fa=p;
}
else
{
tree[i].bro=tree[tree[p].son].bro;
tree[tree[p].son].bro=i;
tree[i].fa=p;
}
}
pretravel(1);
while(m--)
{
char str[5];
int x;
scanf("%s%d",str,&x);
if(str[0]=='o')
{
update(pos[x],pos[x]+son[x],1,n,1);
}
else
{
printf("%d\n",query(pos[x],pos[x]+son[x],1,n,1));
}
}
printf("\n");
}
}