Codeforces 343D WaterTree - 线段树, DFS序
Description
Translated by @Nishikino_Maki from Luogu
行吧是我翻的
- Mad scientist Mike has constructed a rooted tree, which consists of n n vertices. Each vertex is a reservoir which can be either empty or filled with water.
- The vertices of the tree are numbered from 1 to n n with the root at vertex 1. For each vertex, the reservoirs of its children are located below the reservoir of this vertex, and the vertex is connected with each of the children by a pipe through which water can flow downwards.
- Mike wants to do the following operations with the tree:
- Fill vertex v with water. Then v and all its children are filled with water.
- Empty vertex v . Then v and all its ancestors are emptied.
- Determine whether vertex v is filled with water at the moment.
Initially all vertices of the tree are empty.Mike has already compiled a full list of operations that he wants to perform in order. Before experimenting with the tree Mike decided to run the list through a simulation. Help Mike determine what results will he get after performing all the operations.
疯狂科学家Mike培养了一颗有根树,由n个节点组成。每个节点是一个要么装满水要么为空的贮水容器. 树的节点用1~n编号,其中根节点为1.对于每个节点的容器,其子节点的容器均在这一容器下方,并且每个节点都由一根可以向下流水的管道与其子节点连接. Mike想要对这棵树做以下操作:
- 将节点v注满水. 这样v和其子节点都会充满水.
- 将节点v置空. 这样v及其祖先节点(从v到根节点的路径)都会被置空.
- 查询当前节点v是否充满水.
- 初始时,所有节点都为空. Mike已经制定好了他的操作顺序. 在对树进行实验前,他决定先模拟一下操作. 请你帮助Mike得出他操作后的结果.
Input&Output
Input
- The first line of the input contains an integer n ( 1<=n<=500000 ) — the number of vertices in the tree. Each of the following n−1 lines contains two space-separated numbers ai, bi(1<=ai,bi<=n, ai≠bi) — the edges of the tree.
- The next line contains a number q (1 ≤ q ≤ 500000) — the number of operations to perform. Each of the following q lines contains two space-separated numbers ci (1 ≤ ci ≤ 3), vi (1 ≤ vi ≤ n), where ci is the operation type (according to the numbering given in the statement), and vi is the vertex on which the operation is performed.
- It is guaranteed that the given graph is a tree.
- 第一行为一个整数n(1<=n<=500000),为树的节点数;
- 下面的n-1行为两个空格隔开的整数ai,bi(1<=ai, bi<=n),为树的边;
- 下一行为一个整数q(1<=q<=500000),为操作数;接下来q行,两个空格隔开的整数ci(1<=ci<=3),vi(1<=vi<=n),其中ci为操作类型(已给出),vi为被操作的节点.
这意味着给出的图为一棵树.
Output
- For each type 3 operation print 1 on a separate line if the vertex is full, and 0 if the vertex is empty. Print the answers to queries in the order in which the queries are given in the input.
- 对于每一次操作3,如果节点v充满水,单独输出一行1,如果节点v为空,单独输出一行0. 按照操作输入的顺序输出.
Sample
Input
5
1 2
5 1
2 3
4 2
12
1 1
2 3
3 1
3 2
3 3
3 4
1 2
2 4
3 1
3 3
3 4
3 5
Output
0
0
0
1
0
1
0
1
Solution
- 本题我们可以考虑将树形结构转为线性结构,通过DFS序记录每个节点进入和退出的时间,则区间[ intime[v], outtime[v] ]就代表线段上从v到v的所有子节点.
- 如何维护?对于操作1,我们要对子树区间进行区间增加操作,对于操作2,也有类似的操作;操作3是查询操作,再加上上文中记录的线性结构,可以想到用线段树来维护.
- 下面解释一些细节:
- 操作1,可以对区间实现整体加和操作,线段树的函数实现不再赘述。需要注意的是,对于节点的和,应当执行sum=length,而不应该执行+=操作,否则可能出现节点上的数字大于1的情况.
- 操作2,需要对节点及其到根节点的路径置为0,但我们没有记录路径,相应的修改比较麻烦,我们可以考虑先进行单点修改。
为什么单点修改?
- 我们可以对每个节点进行query操作,若结果<length,则意味着子节点中一定存在0,此时将其父节点置为0,因此单点修改可以对其祖先产生影响.从而保证了沿路径所有节点都可以在其子节点被访问时被修改.
- 查询时,若子节点中有0,则该节点为0.若子节点全为1,则该节点为1.
初始状态如何处理?
- 初始时,所有节点全为0,但这并不影响节点的状态,如果一个节点的子节点中有0,说明该子节点没有被修改过,因此我们查询的节点也一定没有被修改过.
- 关于lazy tag
- 我们可以定义lazy的三种状态,0,1,-1,在pushdown时,如果遇到-1,代表没有操作,退出;对于另外两种状态,将子节点的sum值置为lazy*length即可.
其他的一些操作大体和线段树类似.
代码如下:
#include<iostream> #include<cstdio> #define maxn 500010 using namespace std; struct edge{ int to,nxt; edge(){to=0;nxt=0;} }e[maxn<<1]; struct node{ int sum; int lazy; int l,r; int lc,rc; node() { lazy=-1; lc=rc=-1; } }; int link[maxn],edgenum,itime[maxn],otime[maxn],fa[maxn]; int n,op,ed,q,c,v; int dfscnt; void add(int bgn,int end) { edgenum++; e[edgenum].to=end; e[edgenum].nxt=link[bgn]; link[bgn]=edgenum; } inline int rd() { int x=0; bool f=true; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-')f=false; c=getchar(); } while(c>='0'&&c<='9'){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); } return f?x:-x; } void dfs(int cur,int f) { itime[cur]=++dfscnt; for(int i=link[cur];i;i=e[i].nxt) { if(e[i].to==f)continue; fa[e[i].to]=cur; dfs(e[i].to,cur); } otime[cur]=dfscnt; } node tree[maxn<<1]; int cnt; int rt=cnt++; void pushup(int cur) { int lc=tree[cur].lc,rc=tree[cur].rc; tree[cur].sum=tree[lc].sum+tree[rc].sum; tree[cur].l=tree[lc].l; tree[cur].r=tree[rc].r; } void pushup2(int cur) { int lc=tree[cur].lc,rc=tree[cur].rc; tree[cur].sum=tree[lc].sum+tree[rc].sum; } void pushdown(int cur) { if(tree[cur].lazy==-1)return; int lc=tree[cur].lc; int rc=tree[cur].rc; tree[lc].sum=tree[cur].lazy*(tree[lc].r-tree[lc].l+1); tree[rc].sum=tree[cur].lazy*(tree[rc].r-tree[rc].l+1); tree[lc].lazy=tree[cur].lazy; tree[rc].lazy=tree[cur].lazy; tree[cur].lazy=-1; } void build(int l,int r,int cur){ if(l==r){ tree[cur].sum=0; tree[cur].l=tree[cur].r=l; return; } int mid=(l+r)>>1; tree[cur].lc=cnt++; tree[cur].rc=cnt++; build(l,mid,tree[cur].lc); build(mid+1,r,tree[cur].rc); pushup(cur); } void upd(int l,int r,int x,int cur) { if(tree[cur].l>=l&&tree[cur].r<=r) { tree[cur].sum=x*(tree[cur].r-tree[cur].l+1); tree[cur].lazy=x; return; } pushdown(cur); int mid=(tree[cur].l+tree[cur].r)>>1; if(l<=mid)upd(l,r,x,tree[cur].lc); if(r>mid)upd(l,r,x,tree[cur].rc); pushup2(cur); } int query(int l,int r,int cur) { if(tree[cur].l>=l&&tree[cur].r<=r) return tree[cur].sum; pushdown(cur); int mid=(tree[cur].l+tree[cur].r)>>1; int tot=0; if(l<=mid)tot+=query(l,r,tree[cur].lc); if(r>mid)tot+=query(l,r,tree[cur].rc); return tot; } int main() { n=rd(); for(int i=1;i<n;++i){ op=rd(); ed=rd(); add(op,ed); add(ed,op); } dfs(1,0); build(1,n,rt); q=rd(); for(int i=1;i<=q;++i){ c=rd(); if(c==1){ v=rd(); int l=itime[v]; int r=otime[v]; if(query(l,r,rt)<r-l+1&&v!=1)upd(itime[fa[v]],itime[fa[v]],0,rt); upd(itime[v],otime[v],1,rt); } else if (c==2){ v=rd(); upd(itime[v],itime[v],0,rt); } else if(c==3){ v=rd(); int l=itime[v]; int r=otime[v]; if(query(l,r,rt)<r-l+1)printf("0\n"); else printf("1\n"); } } return 0; }
Codeforces 343D WaterTree - 线段树, DFS序的更多相关文章
- Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序
题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s 内存限制:512.0MB 总提交次数:196 AC次数:65 平均分: ...
- BZOJ_3252_攻略_线段树+dfs序
BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...
- 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序
题目大意 Bob有一棵\(n\)个点的有根树,其中\(1\)号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜 ...
- 【bzoj4817】树点涂色 LCT+线段树+dfs序
Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...
- S - Query on a tree HDU - 3804 线段树+dfs序
S - Query on a tree HDU - 3804 离散化+权值线段树 题目大意:给你一棵树,让你求这棵树上询问的点到根节点直接最大小于等于val的长度. 这个题目和之前写的那个给你一棵 ...
- HDU 5692 线段树+dfs序
Snacks Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Sub ...
- Codeforces 343D Water Tree(DFS序 + 线段树)
题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...
- Codeforces 571D - Campus(并查集+线段树+DFS 序,hot tea)
Codeforces 题目传送门 & 洛谷题目传送门 看到集合的合并,可以本能地想到并查集. 不过这题的操作与传统意义上的并查集不太一样,传统意义上的并查集一般是用来判断连通性的,而此题还需支 ...
- Codeforces 877E - Danil and a Part-time Job 线段树+dfs序
给一个有根树,1e5个节点,每个节点有权值0/.1,1e5操作:1.将一个点的子树上所有点权值取反2.查询一个点的子树的权值和 题解: 先深搜整颗树,用dfs序建立每个点对应的区间,等于把树拍扁成 ...
随机推荐
- python select模块详解
要理解select.select模块其实主要就是要理解它的参数, 以及其三个返回值.select()方法接收并监控3个通信列表, 第一个是所有的输入的data,就是指外部发过来的数据,第2个是监控和接 ...
- Shiro入门这篇就够了【Shiro的基础知识、回顾URL拦截】
前言 本文主要讲解的知识点有以下: 权限管理的基础知识 模型 粗粒度和细粒度的概念 回顾URL拦截的实现 Shiro的介绍与简单入门 一.Shiro基础知识 在学习Shiro这个框架之前,首先我们要先 ...
- Git分支(3/5) -- 禁用 Fast Forward 合并
添加一个分支, 并且换到该分支: git checkout -b add-text 然后我再index.html里面添加点文字, 并commit. 然后再修改README.md, 添加文字, comm ...
- 20165230 预备作业3 Linux安装及学习
20165230 预备作业3 Linux安装及学习 安装Linux操作系统 通过学习实践基于VirtualBox虚拟机安装Ubuntu图文教程,开始了虚拟机的安装,根据教程按着步骤一步一步的完成. 遇 ...
- ASP.NET MVC编程——视图
1Razon语法 使用@符号后接C#或VB.NET语句的方式. 基本规则 1)变量 @后直接变量即可 2)代码块 为使用表达式或多行代码,@后跟大括号将多行代码包括在大括号中 3)"+&qu ...
- JavaScript -- 知识点汇总
js语法 1. javascript数据类型 JavaScript拥有动态类型.这意味着相同的变量可用作不同的类型:有 字符串,数字, 布尔值, 对象, 数组,Undefined和Null 对象: v ...
- WebGL 3D 工业隧道监控实战
前言 监控隧道内的车道堵塞情况.隧道内的车祸现场,在隧道中显示当前车祸位置并在隧道口给与提示等等功能都是非常有必要的.这个隧道 Demo 的主要内容包括:照明.风机.车道指示灯.交通信号灯.情报板.消 ...
- poj-1031-fence(不是我写的,我只是想看着方便)
题目大意: 有一个光源位于(0,0)处,一个多边形的围墙.围墙是“全黑”的,不透光也不反射光.距光源r处的光强度为I0=k/r,k为常数. 一块无穷窄高为h的墙上围墙受到的照度为dI=I0*|cosα ...
- 部署腾讯云(CentOS6.6版本,jdk1.7+tomcat8+mysql)
这是从一个大神哪里学到的,用来留下来用以记录 http://blog.csdn.net/qingluoII/article/details/76053736 只是其中有一个地方,我在学习的时候觉得可以 ...
- Algorithm --> 树中求顶点A和B共同祖先
树中求顶点A和B共同祖先 题目: 给定一颗树,以及两个顶点A和B,求最近的共同祖先,和包含的子顶点个数? 比如:给定如下图的树,以及顶点13和8,则共同祖先为3,以3为root的子顶点共有8个