CF1017G The Tree 树链剖分
CF1017G The Tree
树链剖分好题。
乍一看还以为是道沙比题,然后发现修改操作有点不一样。
但是如果你对基本操作还不太熟练,可以看看我的树链剖分总结
有三个操作:
- 从一个点往下染黑,是黑色节点就继续染,一直染到白色节点为止;
- 染白一棵子树;
- 查询一个点的颜色。
主要是第一个操作不好处理。由于每次只询问一个点的信息,考虑把一个点的颜色用从根节点到这个点的最大后缀和来表达:最大后缀和小于零则为白色,反之则为黑色。首先把树上每一个点的权值都定为\(-1\),对于每个1操作,把该点的权值++;对于每个2操作,把一棵子树的权值全都变成\(-1\),并在该子树的根节点减去一个权值,使得大树根节点到子树根节点的最大后缀和恰为\(-1\);对于3查询,查询一个根节点到这个点的最大后缀和,\(<0\)白色,\(\ge 0\)黑色。可以证(shou)明(wan),这样做正确地在\(O(n(log n)^2)\)的复杂度内维护了树上的信息。
如果你不会在树上维护最大后缀和,可以先考虑在区间上维护,用线段树维护一个区间和、一个区间最大后缀和就好了,合并信息的方法就很容易看出了,查询的时候也可以用同样的方法合并,放到树上来之后合并的方法还是没有变。
#include<cstdio>
#include<cctype>
#define R register
#define I inline
using namespace std;
const int S=200003,M=800003,inf=0x3f3f3f3f;
char buf[1000000],*p1,*p2;
I char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,S,stdin),p1==p2)?EOF:*p1++;}
I int rd(){
R int f=0; R char c=gc();
while(c<48||c>57) c=gc();
while(c>47&&c<58) f=f*10+(c^48),c=gc();
return f;
}
struct O{int f,g;};
struct N{int f,g,b;}a[M];
int h[S],s[S],g[S],d[S],t[S],p[S],q[S],r[S],f[S],c,e,n;
I int max(int x,int y){return x>y?x:y;}
O operator+(O x,O y){return (O){max(x.f+y.g,y.f),x.g+y.g};}
I void add(int x,int y){s[++c]=h[x],h[x]=c,g[c]=y;}
I void upd(int k,int l,int r){a[k].f=-1,a[k].g=-(r-l+1),a[k].b=1;}
I void psu(int k,int p,int q){a[k].f=max(a[q].f,a[p].f+a[q].g),a[k].g=a[p].g+a[q].g;}
I void psd(int k,int l,int r){
if(a[k].b){
R int p=k<<1,q=p|1,m=l+r>>1;
upd(p,l,m),upd(q,m+1,r),a[k].b=0;
}
}
void bld(int k,int l,int r){
if(l==r){a[k].f=a[k].g=-1; return ;}
R int p=k<<1,q=p|1,m=l+r>>1;
bld(p,l,m),bld(q,m+1,r),psu(k,p,q);
}
void mdf1(int k,int l,int r,int x,int v){
if(l==r){a[k].f+=v,a[k].g+=v; return ;}
R int p=k<<1,q=p|1,m=l+r>>1;
psd(k,l,r);
if(x<=m) mdf1(p,l,m,x,v);
else mdf1(q,m+1,r,x,v);
psu(k,p,q);
}
void mdf2(int k,int l,int r,int x,int y){
if(x<=l&&r<=y){upd(k,l,r); return ;}
R int p=k<<1,q=p|1,m=l+r>>1;
psd(k,l,r);
if(x<=m) mdf2(p,l,m,x,y);
if(m<y) mdf2(q,m+1,r,x,y);
psu(k,p,q);
}
O qry(int k,int l,int r,int x,int y){
if(x<=l&&r<=y) return (O){a[k].f,a[k].g};
R int p=k<<1,q=p|1,m=l+r>>1;
O o=(O){-inf,0};
psd(k,l,r);
if(x<=m) o=o+qry(p,l,m,x,y);
if(m<y) o=o+qry(q,m+1,r,x,y);
return o;
}
void dfs1(int x,int f){
d[x]=d[f]+1,p[x]=f,t[x]=1;
for(R int i=h[x],y,m=0;i;i=s[i])
if((y=g[i])^f){
dfs1(y,x),t[x]+=t[y];
if(t[y]>m) q[x]=y,m=t[y];
}
}
void dfs2(int x,int t){
f[x]=++e,r[x]=t;
if(q[x]) dfs2(q[x],t);
for(R int i=h[x],y;i;i=s[i])
if((y=g[i])^p[x]&&y^q[x])
dfs2(y,y);
}
I int qry0(int x){
R int o=-inf,v=0; O u;
while(x)
u=qry(1,1,n,f[r[x]],f[x]),o=max(o,u.f+v),v+=u.g,x=p[r[x]];
return o;
}
int main(){
R int Q,i,x,y;
for(n=rd(),Q=rd(),i=2;i<=n;++i)
x=rd(),add(x,i);
dfs1(1,0),dfs2(1,1),bld(1,1,n);
for(i=1;i<=Q;++i){
x=rd(),y=rd();
if(x==1)
mdf1(1,1,n,f[y],1);
if(x==2)
mdf2(1,1,n,f[y],f[y]+t[y]-1),mdf1(1,1,n,f[y],-(qry0(y)+1));
if(x==3)
qry0(y)>=0?printf("black\n"):printf("white\n");
}
return 0;
}
跑的还算快。
CF1017G The Tree 树链剖分的更多相关文章
- [CF1017G]The Tree[树链剖分+线段树]
题意 给一棵一开始 \(n\) 个点全是白色的树,以 \(1\) 为根,支持三种操作: 1.将某一个点变黑,如果已经是黑色则该操作对所有儿子生效. 2.将一棵子树改成白色. 3.询问某个点的颜色. \ ...
- Hdu 5274 Dylans loves tree (树链剖分模板)
Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...
- POJ3237 Tree 树链剖分 边权
POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...
- Query on a tree——树链剖分整理
树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...
- 【BZOJ-4353】Play with tree 树链剖分
4353: Play with tree Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 31 Solved: 19[Submit][Status][ ...
- SPOJ Query on a tree 树链剖分 水题
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
- poj 3237 Tree 树链剖分
题目链接:http://poj.org/problem?id=3237 You are given a tree with N nodes. The tree’s nodes are numbered ...
- Codeforces Round #200 (Div. 1) D Water Tree 树链剖分 or dfs序
Water Tree 给出一棵树,有三种操作: 1 x:把以x为子树的节点全部置为1 2 x:把x以及他的所有祖先全部置为0 3 x:询问节点x的值 分析: 昨晚看完题,马上想到直接树链剖分,在记录时 ...
- poj 3237 Tree 树链剖分+线段树
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
随机推荐
- Entity Framework 6.X实现记录执行的SQL功能
Entity Framework在使用时,很多时间操纵的是Model,并没有写sql语句,有时候为了调试或优化等,又需要追踪Entity framework自动生成的sql(最好还能记录起来,方便出错 ...
- Oracle GoldenGate OGG管理员手册(较早资料)
第一章 系统实现简述 前言 编写本手册的目的是为系统管理员以及相关操作人员提供 Oracle Goldengat 软 件的日常维护和使用的技术参考: 3 ORACLE 第二章 OGG 日常维护操作 ...
- Imagex用法
imagex用来合并/导出wim映像实例 查看wim中包含的所有单个wim实例信息,注意其中的index是唯一的,用来区分不同的wim,导出的时候也通过该index导出相应的wimimagex /in ...
- 全网数据定时备份方案[cron + rsync]
1.1.1. Rsync(远程同步)介绍 [Rsync等价scp cp rm共3个命令的和] 1.什么是Rsync: Linux下面开源的,很快,功能很多,可以实现全量及增量的本地或者远程数据同步 ...
- Linux chattr 命令详解
常见命令参数 A:即Atime,告诉系统不要修改对这个文件的最后访问时间. S:即Sync,一旦应用程序对这个文件执行了写操作,使系统立刻把修改的结果写到磁盘. a:即Append Only,系统只允 ...
- yii 验证码功能的实现
首先知晓我们在使用验证码的时候通常是和我们的表单小部件配合使用首先我们创建model层 新建一个php文件 名字叫做Verifycode.php 要在我们的model层 创建我们的验证码的验证规则,我 ...
- JS 正则 /g 注意事项
JS 正则 /g 注意事项 字数1066 阅读0 评论0 喜欢0 js中正则表达式的全局匹配模式 /g用法详细 瞎扯 使用正则表达式来做表单验证的时候,遇到如下一个鬼东西, 匹配正则的时候,同样的数据 ...
- 026.2 网络编程 UDP聊天
实现,通过socket对象 ##############################################################需求建立UDP发送端:###思路:1.建立可以实 ...
- Python简单实现多级菜单
# -*- coding: utf-8 -*- # @Time : 2018-06-01 13:40 # @Author : 超人 # @Email : huxiaojiu111@gmail.com ...
- 学习HTTP
http://blog.csdn.net/lmh12506/article/details/7794512 HTTP协议是无状态的和Connection: keep-alive的区别 http协议是无 ...