传送门:QAQQAQ

题意:给你一棵树,有三种操作,设所有点本来未感染

1:感染节点i,若i被二次感染,则感染i的儿子(若儿子也被感染,则感染孙子,直到到底或者感染了健康点)

2:使i子树全部健康

3:查询节点x是否被感染

思路:树上的修改查询,很容易想到树链剖分

我们先把所有点的权值设为-1,定义一个点没有感染当且仅当它的最大后缀和小于0(这主要是由操作1想到这种方法,这样对于1操作,把i节点权值+1即可)

对于2操作,在把i子树全部赋成-1时,也要消除i祖先可能有节点大于0对i子树的影响(因为全部健康后要求i子树所有点最大后缀和小于0),所以我们再次对i进行修改,使i节点权值变为$-query(Father[i])-1$,query表示i的最大后缀和,若query是-1,千万不要还是$-query-1$把i赋成了0,应该赋成-1,需要判一下,赛程上就是因为这个滑点100->30,还有若i是根节点第二个改父亲操作不要做,否则RE

代码(从树链剖分模板里HE的,码风很丑,感觉细节挺多,可能是我太弱惹QAQ):

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=202000;
const int inf=(int)2e9; struct node{
int sum,lazy=0,lz,rz,mx;//最大后缀和
}tree[N*4];
int w[N],n,m;
int top[N],f[N],son[N],sz[N],dep[N],p[N];
int id[N],rk[N];
//rk:节点号->树剖序 id:树剖序->节点号 node operator + (node A,node B)
{
node ret;
ret.sum=A.sum+B.sum;
ret.mx=max(A.mx,A.sum+B.mx);
return ret;
} int first[N],nxt[N*2],point[N*2],e=0;
void add_edge(int x,int y)
{
point[e]=y;
nxt[e]=first[x];
first[x]=e++;
} void dfs1(int u)
{
int maxsz=0;
for(int i=first[u];i!=-1;i=nxt[i])
{
int v=point[i];
if(v==f[u]) continue;
f[v]=u; dep[v]=dep[u]+1;
dfs1(v); sz[u]+=sz[v];
if(maxsz<sz[v])
{
maxsz=sz[v];
son[u]=v;
}
}
sz[u]++;
} int cnt=0;
void dfs2(int u,int t)
{
top[u]=t;
rk[u]=++cnt;
id[cnt]=u;
if(!son[u]) return;
dfs2(son[u],t);
for(int i=first[u];i!=-1;i=nxt[i])
{
int v=point[i];
if(v==f[u]||v==son[u]) continue;
dfs2(v,v);
}
} int len(node fa)
{
return fa.rz-fa.lz+1;
} void pushup(node &fa,node ls,node rs)
{
fa.sum=ls.sum+rs.sum;
fa.lz=ls.lz; fa.rz=rs.rz;
fa.mx=max(rs.sum+ls.mx,rs.mx);
} void pushdown(node &fa,node &ls,node &rs)
{
if(!fa.lazy) return;
ls.lazy=fa.lazy; rs.lazy=fa.lazy;
ls.sum=fa.lazy*len(ls); rs.sum=fa.lazy*len(rs);
ls.mx=-1; rs.mx=-1;
fa.lazy=0;
} void build(int x,int l,int r)
{
if(l==r)
{
tree[x].sum=w[id[l]];//线段树维护的是树剖序中的第l个,而传的点是节点序,id:树剖序->节点序
tree[x].lz=l; tree[x].rz=l;
tree[x].mx=w[id[l]];
return;
}
int mid=(l+r)>>1;
build(x+x,l,mid);
build(x+x+1,mid+1,r);
pushup(tree[x],tree[x+x],tree[x+x+1]);
} void update(int x,int l,int r,int L,int R,int upd)
{
if(L<=l&&r<=R)
{
tree[x].sum=upd*len(tree[x]);
if(L!=R) tree[x].lazy=upd;
tree[x].mx=upd;
return;
}
pushdown(tree[x],tree[x+x],tree[x+x+1]);
int mid=(l+r)>>1;
if(mid>=R) update(x+x,l,mid,L,R,upd);
else if(mid<L) update(x+x+1,mid+1,r,L,R,upd);
else
{
update(x+x,l,mid,L,R,upd);
update(x+x+1,mid+1,r,L,R,upd);
}
pushup(tree[x],tree[x+x],tree[x+x+1]);
} node query(int x,int l,int r,int L,int R)
{
node ret;
ret.sum=-inf; ret.mx=-inf;
if(L<=l&&r<=R) return tree[x];
pushdown(tree[x],tree[x+x],tree[x+x+1]);
int mid=(l+r)>>1;
if(mid>=R) return query(x+x,l,mid,L,R);
else if(mid<L) return query(x+x+1,mid+1,r,L,R);
else
{
ret=query(x+x+1,mid+1,r,L,R);
ret=ret+query(x+x,l,mid,L,R);
}
return ret;
} int max_line(int x,int y)
{
node ret;
ret.sum=-inf; ret.mx=-inf;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
if(ret.mx==-inf) ret=query(1,1,n,rk[top[x]],rk[x]);
else ret=ret+query(1,1,n,rk[top[x]],rk[x]);
x=f[top[x]];
//不能两个都跳,可能top深度较浅的会跳过LCA
}
if(rk[x]>rk[y]) swap(x,y);
if(ret.mx==-inf) ret=query(1,1,n,rk[x],rk[y]);
else ret=ret+query(1,1,n,rk[x],rk[y]);
return ret.mx;
} void init()
{
memset(first,-1,sizeof(first));
memset(nxt,-1,sizeof(nxt));
memset(w,-1,sizeof(w));
scanf("%d%d",&n,&m);
dep[1]=1; f[1]=1;
for(int i=2;i<=n;i++)
{
scanf("%d",&p[i]);
add_edge(i,p[i]);
add_edge(p[i],i);
}
dfs1(1);
dfs2(1,1);
//for(int i=1;i<=n;i++) T[rk[i]]=w[i];//枚举节点序->树剖序
build(1,1,n);
} void solve(int opt)
{
//一个子树的dfn序是连续的
int x;
if(opt==1)
{
scanf("%d",&x);
int tmp=query(1,1,n,rk[x],rk[x]).sum+1;
update(1,1,n,rk[x],rk[x],tmp);
}
else if(opt==2)
{
scanf("%d",&x);
update(1,1,n,rk[x],rk[x]+sz[x]-1,-1);
if(x==1) return;
int tmp=min(-max_line(p[x],1)-1,-1);//!!!!!
update(1,1,n,rk[x],rk[x],tmp);
}
else
{
scanf("%d",&x);
int ans=max_line(x,1);
if(ans>=0) puts("black");
else puts("white");
}
} int main()
{
init();
for(int i=1;i<=m;i++)
{
int opt; scanf("%d",&opt);
solve(opt);
}
return 0;
}

CF1017G——The Tree的更多相关文章

  1. CF1017G The Tree 树链剖分

    CF1017G The Tree LG传送门 树链剖分好题. 乍一看还以为是道沙比题,然后发现修改操作有点不一样. 但是如果你对基本操作还不太熟练,可以看看我的树链剖分总结 有三个操作: 从一个点往下 ...

  2. CF1017G The Tree

    /* 这是什么神仙题目QAQ 首先考虑在序列上的问题 先不考虑修改成白色, 一个白点能r被染成黑色 意味着能够找到一个l使得在l-r中的操作1次数大于等于 r - l + 1 我们把初始值覆盖成-1就 ...

  3. [CF1017G]The Tree[树链剖分+线段树]

    题意 给一棵一开始 \(n\) 个点全是白色的树,以 \(1\) 为根,支持三种操作: 1.将某一个点变黑,如果已经是黑色则该操作对所有儿子生效. 2.将一棵子树改成白色. 3.询问某个点的颜色. \ ...

  4. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  5. SAP CRM 树视图(TREE VIEW)

    树视图可以用于表示数据的层次. 例如:SAP CRM中的组织结构数据可以表示为树视图. 在SAP CRM Web UI的术语当中,没有像表视图(table view)或者表单视图(form view) ...

  6. 无限分级和tree结构数据增删改【提供Demo下载】

    无限分级 很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了. 说到无限分级,又要扯到递归调用了.(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据.当然,以 ...

  7. 2000条你应知的WPF小姿势 基础篇<45-50 Visual Tree&Logic Tree 附带两个小工具>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ...

  8. Leetcode 笔记 110 - Balanced Binary Tree

    题目链接:Balanced Binary Tree | LeetCode OJ Given a binary tree, determine if it is height-balanced. For ...

  9. Leetcode 笔记 100 - Same Tree

    题目链接:Same Tree | LeetCode OJ Given two binary trees, write a function to check if they are equal or ...

随机推荐

  1. 在Centos6上安装RabbitMQ的过程(有点坑)

    1.安装依赖环境 yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c++ ...

  2. 090 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 04 使用包进行类管理(2)——导入包

    090 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  3. PADS Layout VX.2.3 灌铜之后没有显示整块铜皮的原因

    操作系统:Windows 10 x64 工具1:PADS Layout VX.2.3 灌铜之后没有显示整块铜皮,如下图所示: 点击菜单Tools > Options...(快捷键:Ctrl + ...

  4. Top Coder 某场Div 2的C题 题解

    前天,我们了解了一下一种叫做树状数组的神奇玩意儿,今天就放一道真题来检验一下自己的学习成果吧! 嗯,题目就是这样的啦. 分析: 这题的暴力大家应该都会打吧. 注意到m小的压批,所以对于每一个m值,我们 ...

  5. 笔记本电脑为什么有时候不用按FN+F1~12也可以控制音量、亮度全部等等

    对于经常要使用F1~F12的用户就很烦,比如编写前端代码的时候想直接按F12检查代码就是不行. 如何取消快捷键? 问题原因: 1.电脑默认使用了快捷键. 2.电脑按了FN+ESC锁定,只限于戴尔的电脑 ...

  6. 关于keytool和jarsigner工具签名的使用小结

    在我们日常Android应用开发中,我们都要对我们开发的apk做签名处理,或者加固,增强我们apk的安全性,防止被逆向反编译,在apk签名这块,我们一般采用JDK自动工具来签名,下面就对相关工具做个简 ...

  7. antd pro table中的文件上传

    概述 示例代码 列表页面 form 页面 model.js service.js 总结 概述 项目中经常会遇到在表格中展示图片的需求(比如展示用户信息时, 有一列是用户的头像). antd pro t ...

  8. 怎样学好 java ?

    浅谈Java的学习之路--怎样学好JAVA ?Java - 近10年来计算机软件发展过程中的传奇,其在众多开发者心中的地位就如"屠龙刀"."倚天剑". Java ...

  9. Celery---一个懂得异步任务,延时任务,周期任务的芹菜

    Celery是什么? celey是芹菜 celery是基于Python实现的模块,用于执行异步延时周期任务的 其结构组成是由 1.用户任务 app 2.管道任务broker用于存储任务 官方推荐red ...

  10. ansible用user/group模块管理受控机上的用户和组(ansible2.9.5)

    一,ansible的user/group模块的用途: ansible的user模块用来实现:生成用户.删除用户等用户的管理ansible的group模块用来实现:生成组.删除组等组的管理 说明:刘宏缔 ...