1. 程式人生 > 其它 >cf877 E. Danil and a Part-time Job(dfs序,線段樹)

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;
}