Codeforces Round #442 (Div. 2) 877 E. Danil and a Part-time Job DFS序 线段树

题目链接: E. Danil and a Part-time Job

题目大意

一棵有根树, 每个节点可以是1或者0, 两种操作:
1. pow v: 将v节点的子树中所有节点的值反置(1变0, 0变1, 相当于异或1)
2. get v: 输出v节点的字数中1的个数
节点个数: 1n2105 , 操作次数: 1q2105

思路

对树的某个子树所有节点进行操作, 很显然要用dfs序将树转换成一条线, 对树进行dfs, 记录下每个节点i的访问起始时间in[i]和结束时间out[i], 这样节点i的序号是in[i], 节点i子树所有节点的序号集合是[in[i], out[i]], 这样将对子树的操作转换成对一个区间的操作, 用线段树处理就好了
dfs处理后的节点的[in[i], out[i]]
这里写图片描述
线段树用懒惰标记实现快速区间更新, 反转时, 区间和变成 区间长度-原来的区间和

代码

GNU C++14 Accepted 327 ms 24400 KB

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int maxn = 2e5 + 100;
int p, t[maxn], in[maxn], out[maxn], n, a[maxn];
vector<int> G[maxn];

void dfs(int s, int & x)
{
    in[s] = x;
    for (int ite : G[s]) dfs(ite, ++x);
    out[s] = x;
}


#define ls l , m , rt << 1
#define rs m + 1 , r , rt << 1 | 1
int sum[maxn << 2], col[maxn << 2];

void pushUp(int rt)
{
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void pushDown(int rt, int m)
{
    if (col[rt])
    {
        col[rt << 1] ^= col[rt];
        col[rt << 1 | 1] ^= col[rt];
        sum[rt << 1] = (m - m / 2) - sum[rt << 1];
        sum[rt << 1 | 1] = m / 2 - sum[rt << 1 | 1];
        col[rt] = 0;
    }
}
void build(int l, int r, int rt)
{
    col[rt] = 0;
    if (l == r)
    {
        sum[rt] = a[l];
    }
    else
    {
        int m = (l + r) / 2;
        build(ls);
        build(rs);
        pushUp(rt);
    }
}
void update(int L, int R, int l, int r, int rt)
{
    if (L <= l && r <= R)
    {
        col[rt] ^= 1;
        sum[rt] = r - l + 1 - sum[rt];
        return ;
    }
    pushDown(rt, r - l + 1);
    int m = (l + r) / 2;
    if (L <= m) update(L, R, ls);
    if (R > m) update(L, R, rs);
    pushUp(rt);
}

int query(int L, int R, int l, int r, int rt)
{
    if (L <= l && r <= R) return sum[rt];
    pushDown(rt, r - l + 1);
    int m = (l + r) / 2;
    int ret = 0;
    if (L <= m) ret += query(L, R, ls);
    if (R > m) ret += query(L, R, rs);
    return ret;
}

int main()
{
    scanf("%d", &n);
    for (int i = 2; i <= n; ++i)
    {
        scanf("%d", &p);
        G[p].push_back(i);
    }
    int x = 1;
    dfs(1, x);

    for (int i = 1; i <= n; ++i)
    {
        scanf("%d", &a[in[i]]);//a[x]记录dfs序号为x的节点的值
    }
    build(1, n, 1);
    int q;
    scanf("%d", &q);
    char op[10];

    while (q--)
    {
        scanf("%s%d", op, &x);
        if (op[0] == 'g')
        {
            printf("%d\n", query(in[x], out[x], 1, n, 1));
        }
        else
        {
            update(in[x], out[x], 1, n, 1);
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/litmxs/article/details/78348378