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

来源:互联网 发布:mysql 多字段排序 编辑:程序博客网 时间:2024/05/16 02:56

题目链接: 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 | 1int 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;}
阅读全文
0 0
原创粉丝点击