cf877 E. Danil and a Part-time Job(dfs序,线段树)
题意:
一棵点权为0/1的树,实现两种操作:反转 u-子树 中的所有数、查询 u-子树 中1的数量
思路:
一次dfs求出三个数组 dfn、L、R。dfn为原数组按dfs序排列,L为节点 i 的dfs先序,R为节点 i 的一种奇怪的dfs后序。每个节点的R与它的最右边的子节点的R相同。
相当于把原数组按dfs先序重新排序,\([L(u),R(u)]\) 就是 u-子树
对于每次修改把sum变成区间长度减sum即可
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, q, val[N];
int h[N], e[N], ne[N], idx;
void add(int a, int b) {
    e[++idx] = b, ne[idx] = h[a], h[a] = idx;
}
int cnt, L[N], R[N], dfn[N];
void dfs(int u)
{
    dfn[++cnt] = u;
    L[u] = cnt;
    for(int i = h[u]; i; i = ne[i]) dfs(e[i]);
    R[u] = cnt;
}
struct node {
    int l, r; int sum, tag; //tag=1表示左右子节点要变
} tr[N*4];
void pushup(int u)
{
    tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;
}
void pushdown(int u)
{
    node &root = tr[u], &left = tr[u<<1], &right = tr[u<<1|1];
    if(root.tag) //!
    {
        left.tag ^= 1, right.tag ^= 1;
        left.sum = left.r-left.l+1 - left.sum;
        right.sum = right.r-right.l+1 - right.sum;
        root.tag = 0;
    }
}
void build(int u, int l, int r)
{
    if(l == r) tr[u] = {l, r, val[dfn[l]]}; //!
    else
    {
        tr[u] = {l, r};
        int mid = l + r >> 1;
        build(u<<1, l, mid), build(u<<1|1, mid+1, r);
        pushup(u);
    }
}
void modify(int u, int l, int r)
{
    if(tr[u].l >= l && tr[u].r <= r) //!
    {
        tr[u].tag ^= 1;
        tr[u].sum = tr[u].r-tr[u].l+1 - tr[u].sum;
    }
    else
    {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if(l <= mid) modify(u<<1, l, r);
        if(r > mid) modify(u<<1|1, l, r);
        pushup(u);
    }
}
int query(int u, int l, int r)
{
    if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
    pushdown(u);
    int res = 0, mid = tr[u].l + tr[u].r >> 1;
    if(l <= mid) res += query(u<<1, l, r);
    if(r > mid) res += query(u<<1|1, l, r);
    return res;
}
signed main()
{
    scanf("%d", &n);
    for(int i = 2, p; i <= n; i++) scanf("%d", &p), add(p, i);
    for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
    dfs(1); build(1, 1, n);
    scanf("%d", &q); while(q--) {
        char op[5]; int x; scanf("%s%d", op, &x);
        if(op[0] == 'g') printf("%d\n", query(1, L[x], R[x]));
        else modify(1, L[x], R[x]);
    }
    return 0;
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号