题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4969
题意很简单。。
分析:先作一次DFS求出每个点的起、末位置(时间戳),然后就是线段树区间取反。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
inline int L(int &x) {return x<<1; }
inline int R(int &x) {return x<<1|1; }
#define leson L(root),le,mid
#define rison R(root),mid+1,ri
const int maxn=5+100000;
int n,m;
vector<int>adj[maxn];
int st[maxn],en[maxn],indd;
void dfsAA(int a)
{
st[a] = ++indd;
int s,f;
for(s=adj[a].size(),f=0; f < s; f++)
dfsAA(adj[a].at(f));
en[a] = indd;
}
struct TREE
{
int sum;
bool fg;
}T[maxn*4];
void f_build(int root,int le,int ri)
{
T[(root)].fg = 0;
T[(root)].sum = 0;
if(le == ri)
return ;
int mid=(le+ri)>>1;
f_build(leson);
f_build(rison);
}
void f_pushdown(int root,int len)
{
if(T[root].fg)
{
T[L(root)].fg ^= 1;
T[L(root)].sum = (len>>1)+(len&1)-T[L(root)].sum;
T[R(root)].fg ^= 1;
T[R(root)].sum = (len>>1)-T[R(root)].sum;
T[(root)].fg = 0;
}
}
void f_maintain(int root,int len)
{
T[(root)].sum = T[L(root)].sum+T[R(root)].sum;
}
int Mle,Mri;
void f_update(int root,int le,int ri)
{
if(Mle <= le && ri <= Mri)
{
T[(root)].fg ^= 1;
T[(root)].sum = ri-le+1-T[(root)].sum;
return ;
}
f_pushdown(root, ri-le+1);
int mid=(le+ri)>>1;
if(Mle <= mid)
f_update(leson);
if(Mri > mid)
f_update(rison);
f_maintain(root, ri-le+1);
}
int Qle,Qri;
int f_query(int root,int le,int ri)
{
if(Qle <= le && ri <= Qri)
return T[root].sum;
f_pushdown(root, ri-le+1);
int mid=(le+ri)>>1, ans=0;
if(Qle <= mid)
ans += f_query(leson);
if(Qri > mid)
ans += f_query(rison);
return ans;
}
void cyh()
{
indd = 0;
dfsAA(1);
f_build(1, 1,n);
char ss[3];
int x;
while(m--)
{
scanf("%s %d", ss,&x);
if(ss[0] == 'o')
{
Mle=st[x], Mri=en[x];
f_update(1, 1,n);
}
else
{
Qle=st[x], Qri=en[x];
printf("%d\n", f_query(1,1,n));
}
}
}
int main()
{
int e,fax;
while(scanf("%d %d", &n,&m)+1)
{
for(e=1; e <= n; e++)
adj[e].clear();
for(e=2; e <= n; e++)
{
scanf("%d", &fax);
adj[fax].push_back(e);
}
cyh();
puts("");
}
return 0;
}