Codeforces 877E Danil and a Part-time Job
来源:互联网 发布:大学生消费数据分析 编辑:程序博客网 时间:2024/05/29 15:56
本题的做法是dfs序线段树。
1.什么是dfs序?
dfs从根节点遍历整棵树的过程中经过的节点编号的顺序就是dfs序。
2.如何将dfs序与线段树结合在一起?
对得到的dfs序与1-n进行映射,可以得到一个初始数组num。将dfs序中的第i个节点的标号记为x,那么num[i]表示的就是节点x上灯泡的开关情况。不难发现同一颗子树上的所有节点在dfs序中代表一个连续的区间。那么,以x为根节点子树灯泡情况的反转其实就是num数组中一段连续区间全部异或上1。那么就是一颗简单的区间修改区间查询线段树啦
下面贴上AC代码
#include<bits/stdc++.h>#define maxn 200000 + 10using namespace std;struct node { int sum;//当前区间的灯泡开启数 int lazy;}tree[maxn << 2];int pos[maxn], npos[maxn], cnt;//pos用来记录节点x映射后的位置p npos用于记录位置p所代表的节点xint st[maxn],num[maxn];//记录各个节点的初始灯泡开关情况 以及以x节点为根节点的子树中含有的节点数int n, tmp;vector<int>e[maxn];void dfs(int x)//找出dfs序列{ num[x] = 1; pos[x] = ++cnt; npos[cnt] = x; for (int i = 0; i < e[x].size(); i++) { dfs(e[x][i]); num[x] += num[e[x][i]]; //统计以x为根节点的子树的节点数目 }}void build(int x, int L, int R)//普通的线段树建树过程{ if (L == R) { tree[x].sum = st[npos[L]];//节点编号为npos[L]的节点上灯泡的亮暗情况 return; } int mid = L + R >> 1; build(x << 1, L, mid); build(x << 1 | 1, mid + 1, R); tree[x].sum = tree[x << 1].sum + tree[x << 1 | 1].sum;}void update(int cur, int L, int R)//向下更新{ int mid = L + R >> 1; tree[cur << 1].sum = mid - L + 1 - tree[cur << 1].sum;//左子树 tree[cur << 1 | 1].sum = R - mid - tree[cur << 1 | 1].sum; tree[cur << 1].lazy ^= 1;//节点传递到左右孩子 tree[cur << 1 | 1].lazy ^= 1; tree[cur].lazy = 0;//向下更新完成}int query(int cur, int L, int R, int x, int y) //由于dfs序,如果区间长度y-x+1等于以x为根节点的子树的节点数,可以保证区间[x,y]上的所有点均属于一颗子树{ if (x == L&&y == R) return tree[cur].sum; int mid = L + R >> 1; if (tree[cur].lazy) update(cur, L, R); if (mid >= y)return query(cur << 1, L, mid, x, y);//向左查询 else if (mid + 1 <= x)return query(cur << 1 | 1, mid + 1, R, x, y);//向右查询 else return query(cur << 1, L, mid, x, mid) + query(cur << 1 | 1, mid + 1, R, mid + 1, y);}void modify(int cur, int L, int R, int x, int y){ if (L == x&&R == y) { tree[cur].sum = y - x + 1 - tree[cur].sum; tree[cur].lazy ^= 1; return; } int mid = L + R >> 1; if (tree[cur].lazy)update(cur, L, R); if (mid >= y)modify(cur << 1, L, mid, x, y);//向左查询 else if (mid + 1 <= x)modify(cur << 1 | 1, mid + 1, R, x, y); else modify(cur << 1, L, mid, x, mid), modify(cur << 1 | 1, mid + 1, R, mid + 1, y); tree[cur].sum = tree[cur << 1].sum + tree[cur << 1 | 1].sum;}int main(){ int n; scanf("%d", &n); for (int i = 2; i <= n; i++) { scanf("%d", &tmp); e[tmp].push_back(i);//建立以1为根节点的树 } for (int i = 1; i <= n; i++)scanf("%d", &st[i]);//记录n个节点的初始灯泡开关情况 dfs(1); build(1, 1, n);//线段树建树 int q; scanf("%d", &q); char ord[15]; int p; while (q--) { scanf("%s%d", ord, &p); if (ord[0] == 'g')printf("%d\n", query(1, 1, n, pos[p], pos[p] + num[p] - 1)); else modify(1, 1, n, pos[p], pos[p] + num[p] - 1); }}
阅读全文
0 0
- Codeforces 877E Danil and a Part-time Job
- Codeforces 877E Danil and a Part-time Job【Dfs序+线段树】
- Codeforces-877E:Danil and a Part-time Job(DFS序列+线段树)
- Codeforces 877 E Danil and a Part-time Job(线段树+dfs序)
- Codeforces Round #877 (Div. 2) E. Danil and a Part-time Job
- [codeforces] 877E. Danil and a Part-time Job(DFS序+线段树)
- codeforces 877E. Danil and a Part-time Job (DFS序列+线段树)
- CodeForces 877E Danil and a Part-time Job (dfs序+线段树)
- code forces E. Danil and a Part-time Job
- 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序】
- Codeforces Round #442 (Div. 2) 877 E. Danil and a Part-time Job DFS序 线段树
- codeforces 877 problem E Danil and a Part-time Job 【dfs序 + 线段树区间异或修改】
- CF#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序+树链剖分+线段树区间^
- Codeforces Round #442 (Div. 2) E. Danil and a Part-time Job (dfs序+线段树)
- Codeforces Round #442E-dfs序&线段树的区间更新区间查询-Danil and a Part-time Job
- Django xadmin使用自定义列表
- Birthday Paradox LightOJ
- 低价购买
- PTA 7-1 一元多项式的乘法与加法运算
- 深度强化学习 ( DQN ) 初探
- Codeforces 877E Danil and a Part-time Job
- 欢迎使用CSDN-markdown编辑器
- Django xadmin开启搜索功能
- PTA 7-2 一元多项式求导
- 每天一个linux命令(15):tail 命令
- PTA 7-3 银行业务队列简单模拟
- C++ Primer 学习笔记(第二章)
- 相对和绝对路径,cd命令,创建和删除目录mkdir/rmdir, rm命令
- Android蓝牙开发小实例—打开关闭蓝牙