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; }
相关文章推荐
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job (dfs序 + 线段树)
- codeforces 877 problem E Danil and a Part-time Job 【dfs序 + 线段树区间异或修改】
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job (dfs序树型转线性 线段树区间修改区间查询)
- Codeforces Round #442 (Div. 2)-E-Danil and a Part-time Job(DFS序+线段树区间更新)
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job DFS序+树链剖分+线段树区间^
- Codeforces Round #442 (Div. 2) Danil and a Part-time Job
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job DFS序+树链剖分+线段树区间^
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job DFS序+树链剖分+线段树区间^
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job DFS序+树链剖分+线段树区间^
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job【线段树+dfs序】
- 简单树刨+线段树模板 877E - Danil and a Part-time Job
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job DFS序+树链剖分+线段树区间^
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job DFS序+树链剖分+线段树区间^
- Codeforces 877 E Danil and a Part-time Job(线段树+dfs序)
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job DFS序+树链剖分+线段树区间^
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job (dfs序+线段树)
- Danil and a Part-time Job codeforces dfs序,线段树
- Codeforces Round #442E-dfs序&线段树的区间更新区间查询-Danil and a Part-time Job
- Codeforces Round #877 (Div. 2) E. Danil and a Part-time Job