您的位置:首页 > 其它

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

2017-10-26 00:10 567 查看

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

题目大意

一棵有根树, 每个节点可以是1或者0, 两种操作:

1. pow v: 将v节点的子树中所有节点的值反置(1变0, 0变1, 相当于异或1)

2. get v: 输出v节点的字数中1的个数

节点个数: 1≤n≤2⋅105, 操作次数: 1≤q≤2⋅105

思路

对树的某个子树所有节点进行操作, 很显然要用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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐