codeforces #343d water tree(dfs+线段树)
来源:互联网 发布:黑客获取数据 编辑:程序博客网 时间:2024/05/17 03:07
原题链接:http://codeforces.com/contest/343/problem/D
标签:线段树,dfs
大致题意:(搬运自dm的ppt)
这道题的解法如果没看过题解,是比较难想到的。这道题的解法就是读入完所有的树边后,用dfs搜一遍,得到每个节点的的儿子所在的区间,用in和out来表示。然后这道题就可以转化为线段树的问题。
那么如何实现三种操作呢?我们可以对于每个节点维护sum和f两个值。我们设用1表示该节点有水,0表示该节点没水,那么sum表示该点及其所有儿子的值的总和。用f来维护该点及其所有儿子是否都有(没)水。
对于操作1,如果该点存在值为0的儿子,那么把该点的父亲赋为0(想一想,为什么),然后进行一次区间修改即可。
对于操作2,直接将该点标记为空。
对于查询,将该点用query去查询已该点为根,有多少叶子节点的值为1,将该值与它的叶子节点数进行比较,即可得出子树内是否有节点值为0。如有,输出0;否则输出1。
这道题建议大家在调试时使用静态调试,不然需要调试很久(我自己就是这样)。
附上代码
#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#define maxn 500050#define pb push_backusing namespace std;struct node{ int l,r,f,sum; };int n,i,u,v,top,q; int in[maxn+5],out[maxn+5],fa[maxn+5],dfn,vis[maxn+5]; //fa数组记录每个点的父亲 vector<int> t[maxn]; int ci,vi;node tree[maxn*4+5];void dfs(int x,int fat){ in[x]=++dfn; fa[x]=fat; vis[x]=1; for(int h=0;h<t[x].size();h++) if (vis[t[x][h]]==0) dfs(t[x][h],x); out[x]=dfn;}void pushdown(int x) //利用f拆分计算sum { if (tree[x].f!=-1) //如果l~r全部已有水 { tree[x*2].f=tree[x*2+1].f=tree[x].f; tree[x*2].sum=(tree[x*2].r-tree[x*2].l+1)*tree[x].f; tree[x*2+1].sum=(tree[x*2+1].r-tree[x*2+1].l+1)*tree[x].f; tree[x].f=-1; } } void build(int x,int l,int r){ tree[x].l=l; tree[x].r=r; tree[x].f=-1; tree[x].sum=0; if (l!=r) { int mid=(l+r)/2; build(x*2,l,mid); build(x*2+1,mid+1,r); }}void update(int x,int l,int r,int val) //区间修改 { if (l<=tree[x].l&&tree[x].r<=r) { tree[x].f=val; tree[x].sum=val*(tree[x].r-tree[x].l+1); } else { pushdown(x); int mid=(tree[x].l+tree[x].r)/2; if (l<=mid) update(x*2,l,r,val); if (r>mid) update(x*2+1,l,r,val); tree[x].sum=tree[x*2].sum+tree[x*2+1].sum; }}int query(int x,int l,int r){ int maxl,minr; if (tree[x].f!=-1) { maxl=max(l,tree[x].l); minr=min(r,tree[x].r); return tree[x].f*(minr-maxl+1); } if (l<=tree[x].l&&tree[x].r<=r) return tree[x].sum; else { int num=0; int mid=(tree[x].l+tree[x].r)/2; if (l<=mid) num+=query(x*2,l,r); if (r>mid) num+=query(x*2+1,l,r); return num; }}int main(){ scanf("%d",&n); memset(fa,0,sizeof(fa)); memset(vis,0,sizeof(vis)); for (i=1;i<n;i++) scanf("%d%d",&u,&v),t[u].pb(v),t[v].pb(u); dfn=0; dfs(1,0); build(1,1,dfn); scanf("%d",&q); while (q--) { scanf("%d%d",&ci,&vi); if (ci==1) { if (query(1,in[vi],out[vi])<(out[vi]-in[vi]+1)&&fa[vi]!=0) //判断是否有儿子为空,并且它本身不是根节点 update(1,in[fa[vi]],in[fa[vi]],0); //将其父亲标记为空 update(1,in[vi],out[vi],1); //将其所有儿子标记为有水 } if (ci==2) update(1,in[vi],in[vi],0); //将该点标记为空 if (ci==3) if (query(1,in[vi],out[vi])<(out[vi]-in[vi]+1)) printf("0\n"); else printf("1\n"); } return 0;}
0 0
- codeforces #343d water tree(dfs+线段树)
- Codeforces 343D Water Tree dfs序+线段树
- 【Codeforces 343D】Water Tree dfs序建树+线段树
- [dfs序+线段树] codeforces 343D. Water Tree
- CodeForces 343D Water Tree(dfs序 线段树)
- CodeForces 343D Water Tree(dfs序+线段树区间更新)
- 【CodeForces】343D Water Tree 线段树
- Codeforces 343D Water Tree【思维+Dfs序+线段树】好题!
- Codeforces Round #200 (Div. 1) D. Water Tree(dfs序+线段树)
- CodeForces 343D Water Tree(树链剖分+dfs时间戳)
- CodeForces 343D Water Tree(树链剖分+dfs时间戳)
- Codeforces Round #200 (Div. 1)D. Water Tree 【dfs序+线段树】
- 文章标题 Coderforces 343D : Water Tree(dfs序+线段树)
- Codeforces Round 200 Div1 D Water Tree (树上线段树)
- codeforces 343 D. Water Tree (树链剖分)
- Codeforces-343D:Water Tree(树链剖分)
- Codeforces 343D Water Tree
- CodeForces 343D Water Tree
- h3416最大流(未解决)
- web基础之Servlet执行过程
- leetcode-two sum
- 代理模式【介绍、静态代理、动态代理、入门、应用】
- 思科产品线
- codeforces #343d water tree(dfs+线段树)
- 精确小数点后两位
- 金融业对区块链必须有足够认识
- Yii 1.1使用函数updaAll方法
- 按照堆排序的方式原地进行升序排列
- jquery中的ajax方法详解
- OpenCV机器学习算法学习
- ASP.Net学习笔记015--ASP.Net中使用Cookie
- 通过异或快速找到不同的字符元素