题目链接:https://cn.vjudge.net/problem/CodeForces-877E
题目大意
有一棵以1位根节点的树,每个节点都有一盏灯,或亮或灭,m次操作,get x,表示求x以及其子树中,所有亮着的灯的数量,pow x,表示把x以及其子树灯的状态改变,即1变为0,0变为1。
分析
通过这个题学会了dfs序。dfs序的思想就是,从根节点开始dfs,记下每个节点第一次遇到以及最后一次遇到时的序号,数组in[]表示第一次遇到,数组out[]表示最后一次遇到。那么在遍历的过程当中,当走到某个节点的时候,一定是先把它的子树遍历完,然后返回到上一级,假设遇到x节点的时候,序号是2,x子树共有4个节点,当遍历完所有子树节点时,序号变为6,那么2--6这个区间就可以表示x以及其子树,这样就可以放到线段树里面解决问题了。
如图,假设先从1开始,先走2,那么第一次遇到2号节点的时候,序号是2,其次是子树,4号节点对应序号3,5号对应4,6号对应5,那么2--5,就是2号节点及其子树的区间这样就能放到线段树里面了。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 200010;
int n, m, cnt, tot;
int in[N], out[N], head[N], t[N], num[N];
struct node{
int l, r, sum, lazy;
}tr[N<<2];
struct Edge{
int to, nxt;
}edge[N];
void add(int a, int b)
{
edge[cnt].to = b;
edge[cnt].nxt = head[a];
head[a] = cnt++;
}
void pushup(int m)
{
tr[m].sum = tr[m<<1].sum + tr[m<<1|1].sum;
}
void pushdown(int m)
{
if(tr[m].lazy)
{
tr[m<<1].lazy ^= 1;
tr[m<<1|1].lazy ^= 1;
tr[m<<1].sum = tr[m<<1].r - tr[m<<1].l + 1 - tr[m<<1].sum;
tr[m<<1|1].sum = tr[m<<1|1].r - tr[m<<1|1].l + 1 - tr[m<<1|1].sum;
tr[m].lazy = 0;
}
}
void build(int m, int l, int r)
{
tr[m].l = l;
tr[m].r = r;
tr[m].lazy = 0;
if(l == r)
{
tr[m].sum = t[num[l]];
return ;
}
int mid = (l + r) >> 1;
build(m<<1, l, mid);
build(m<<1|1, mid + 1, r);
pushup(m);
}
void updata(int m, int l, int r)
{
if(tr[m].l == l && tr[m].r == r)
{
tr[m].sum = r - l + 1 - tr[m].sum;
tr[m].lazy ^= 1;
return ;
}
pushdown(m);
int mid = (tr[m].l + tr[m].r) >> 1;
if(r <= mid) updata(m<<1, l, r);
else if(l > mid) updata(m<<1|1, l, r);
else
{
updata(m<<1, l, mid);
updata(m<<1|1, mid + 1, r);
}
pushup(m);
}
int query(int m, int l, int r)
{
if(tr[m].l == l && tr[m].r == r) return tr[m].sum;
pushdown(m);
int mid = (tr[m].l + tr[m].r) >> 1;
if(r <= mid) return query(m<<1, l, r);
else if(l > mid) return query(m<<1|1, l, r);
else return query(m<<1, l, mid) + query(m<<1|1, mid + 1, r);
}
void dfs(int x)
{
in[x] = ++tot;//第一次遇到
num[tot] = x;//num[tot]=x表示在新的序列中,tot这个点是原先的x这个点
for(int i = head[x]; i != -1; i = edge[i].nxt)
dfs(edge[i].to);
out[x] = tot;//最后一次遇到
}
int main()
{
scanf("%d", &n);
cnt = tot = 0;
memset(head, -1, sizeof head);
for(int i = 2; i <= n; i++)
{
int p;
scanf("%d", &p);
add(p, i);
}
for(int i = 1; i <= n; i++) scanf("%d", &t[i]);
dfs(1);
build(1, 1, tot);
scanf("%d", &m);
char s[2];
int x;
while(m--)
{
scanf("%s %d", &s, &x);
if(s[0] == 'g') printf("%d\n", query(1, in[x], out[x]));
else updata(1, in[x], out[x]);
}
return 0;
}