E. Danil and a Part-time Job
做法
先dfs一遍原来的树,求出每个节点dfs先后顺序,使一个节点u和它的子节点的dfn在一个连续的,长度为size[u]的区间内,建立线段树。对于懒标签,每次于1进行异或从而改变开关的状态
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define mid (l + r >> 1)
#define len r - l + 1
using namespace std;
const int N = 2e5 + 10;
int n, m, tot = 0, cnt = 0;
//dfn是dfs的顺序,pre相当于dfn的反函数
//size[u]是u子树的大小
//shift是每个灯的处始状态
int head[N], dfn[N], pre[N], size[N], shift[N];
//线段树,4倍大小
int sum[N << 2], add[N << 2];
struct edge{
int to, nxt;
}e[N << 1];
inline void add_edge(int u, int v){
e[++tot] = {v, head[u]};
head[u] = tot;
}
inline int read(){
int x = 0, op = 1;
char ch = getchar();
while (!isdigit(ch)){
if (ch == '-') op = -1; ch = getchar();
}
while (isdigit(ch)){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * op;
}
inline void dfs(int u, int fa){
dfn[++cnt] = u;
pre[u] = cnt;
size[u] = 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v == fa) continue;
dfs(v, u);
size[u] += size[v];
}
}
inline void push_up(int i){
sum[i] = sum[i << 1] + sum[i << 1|1];
}
inline void push_down(int i, int l, int r){
if (add[i] == 0) return;
add[i << 1] ^= 1;
add[i << 1|1] ^= 1;
sum[i << 1] = mid - l + 1 - sum[i << 1];
sum[i << 1|1] = r - mid - sum[i << 1|1];
add[i] = 0;
}
inline void buildTree(int i, int l, int r){
if (l == r){
sum[i] = shift[dfn[l]];
return;
}
buildTree(i << 1, l, mid);
buildTree(i << 1|1, mid + 1, r);
push_up(i);
}
inline void change(int i, int l, int r, int crtl, int crtr){
if (crtl > r || crtr < l)
return;
if (crtl <= l && crtr >= r){
sum[i] = len - sum[i];
add[i] ^= 1;
return;
}
push_down(i, l, r);
if (mid >= crtl)
change(i << 1, l, mid, crtl, crtr);
if (mid < crtr)
change(i << 1|1, mid + 1, r, crtl, crtr);
push_up(i);
}
inline int query(int i, int l, int r, int crtl ,int crtr){
if (crtl > r || crtr < l)
return 0;
if (crtl <= l && crtr >= r)
return sum[i];
push_down(i, l, r);
int res = 0;
if (mid >= crtl)
res += query(i << 1, l, mid, crtl, crtr);
if (mid < r)
res += query(i << 1|1, mid + 1, r, crtl, crtr);
return res;
}
void solve(){
char op[4] = {0};
int x = 0;
scanf("%s%d", op, &x);
if (op[0] == 'p')
change(1, 1, n, pre[x], pre[x] + size[x] - 1);
else
printf("%d\n", query(1, 1, n, pre[x], pre[x] + size[x] - 1));
}
int main() {
n = read();
for (int i = 2, x; i <= n; ++i) {
x = read();
add_edge(i, x), add_edge(x, i);
}
for (int i = 1; i <= n; ++i) {
shift[i] = read();
}
dfs(1, 0);
buildTree(1, 1, n);
m = read();
while (m--)
solve();
return 0;
}