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 ...
随机推荐
- 转:HTTP Status 404(The requested resource is not available)的几种解决方法
原文地址 原因:servlet没有配置正确 ,查看web.xml确认正确,以及自己的请求路径正确 在IE中提示“404”错误有以下三种情况 1.未部署Web应用 2.URL输入错误 排错方法: 首先, ...
- swift版的元组
swift版的元组 说明 元组的内容并不多,使用的话跟普通变量类似,以下是测试源码: // // ViewController.swift // Tuples // // Created by You ...
- APUE8进程控制 fork vfork exec
- Android混合式开发(Hybrid)
安卓混合式开发(Hybrid) 1 环境搭建 1.1 首先,下载 Android Studio (Intellij Idea) 下载地址:http://www.android-studio.org/ ...
- 【问题记录】centos 开机启动命令未执行
查看日志 /var/log/boot.log 看具体原因,有可能脚本执行有问题, 当你在系统已经启动的时候,脚本执行没问题不代表开机启动能运行
- Junit之测试顺序---FixMethodOrder
参考:http://www.cnblogs.com/lukehuang/archive/2013/08/27.html Brief Junit 4.11里增加了指定测试方法执行顺序的特性 测试类的执行 ...
- JAVA反射机制教程-获取类对象
1. 什么是类对象 类对象,就是用于描述这种类,都有什么属性,什么方法的 2. 获取类对象 获取类对象有3种方式(1). Class.forName(2). Hero.class(3). new He ...
- jenkins ansible
ansible-playbook - hosts: test remote_user: root vars: warpath: "/root/.jenkins/workspace/172.1 ...
- Js 运行机制 event loop
Js - 运行机制 (Even Loop) Javascript 的单线程 - 引用思否的说法: JavaScript的一个语言特性(也是这门语言的核心)就是单线程.什么是单线程呢?简单地说就是同一时 ...
- python 模拟126邮箱登陆
#coding=utf-8from selenium import webdriverimport time mydriver=webdriver.Firefox()mydriver.get(&quo ...