CF1017G The Tree
一棵树,每个点为黑点或白点。一开始全是白点。
支持维护三个操作:1、把\(x\)子树中包含\(x\)的极大黑连通块找出来,把所有点儿子染黑(如果\(x\)为白色直接将\(x\)染成黑色)。2、将一棵子树染白。3、询问一个点的颜色。
\(n,Q\le 10^5\)
考虑怎么处理第一个操作。
假设没有操作二,每次在操作一中给\(x\)加一,考虑询问出黑点的条件。
玩一下可以发现:\(x\)为黑点,当且仅当存在一个祖先\(y\),满足\(val(y,x)\ge dis(y,x)\)。右边移项过去,相当于每个节点一开始权值为\(-1\),询问的时候是询问根到\(x\)的最大后缀和,判断其是否大于等于\(0\)。
接下来的问题是处理第二个询问。直接算出\(x\)到祖先的最大后缀和,在\(x\)处抵消,然后给\(x\)的子树全部赋值为\(-1\)即可。
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100005
#define INF 1000000000
int n;
struct EDGE{
int to;
EDGE *las;
} e[N];
int ne;
EDGE *last[N];
int fa[N],siz[N],dep[N],hs[N],top[N],in[N],out[N],nowdfn;
void dfs1(int x){
siz[x]=1;
dep[x]=dep[fa[x]]+1;
for (EDGE *ei=last[x];ei;ei=ei->las){
dfs1(ei->to);
siz[x]+=siz[ei->to];
if (siz[ei->to]>siz[hs[x]])
hs[x]=ei->to;
}
}
void dfs2(int x,int t){
top[x]=t;
in[x]=++nowdfn;
if (hs[x]){
dfs2(hs[x],t);
for (EDGE *ei=last[x];ei;ei=ei->las)
if (ei->to!=hs[x])
dfs2(ei->to,ei->to);
}
out[x]=nowdfn;
}
struct info{int sum,mx;} s[N*4];
info merge(info a,info b){return (info){a.sum+b.sum,max(a.mx+b.sum,b.mx)};}
int tag[N*4];
void init(int k,int l,int r){
if (l==r){
s[k]={-1,-1};
return;
}
int mid=l+r>>1;
init(k<<1,l,mid);
init(k<<1|1,mid+1,r);
s[k]=merge(s[k<<1],s[k<<1|1]);
}
void gt(int k,int len){
tag[k]=-1;
s[k]={-len,-1};
}
void pd(int k,int l,int r){
if (tag[k]==-1){
int mid=l+r>>1;
gt(k<<1,mid-l+1);
gt(k<<1|1,r-mid);
tag[k]=0;
}
}
info res;
void query(int k,int l,int r,int st,int en){
if (st<=l && r<=en){
res=merge(s[k],res);
return;
}
pd(k,l,r);
int mid=l+r>>1;
if (mid<en) query(k<<1|1,mid+1,r,st,en);
if (st<=mid) query(k<<1,l,mid,st,en);
}
void add(int k,int l,int r,int x,int c){
if (l==r){
s[k].sum+=c;
s[k].mx+=c;
return;
}
pd(k,l,r);
int mid=l+r>>1;
if (x<=mid) add(k<<1,l,mid,x,c);
else add(k<<1|1,mid+1,r,x,c);
s[k]=merge(s[k<<1],s[k<<1|1]);
}
void clear(int k,int l,int r,int st,int en){
if (st<=l && r<=en){
gt(k,r-l+1);
return;
}
pd(k,l,r);
int mid=l+r>>1;
if (st<=mid) clear(k<<1,l,mid,st,en);
if (mid<en) clear(k<<1|1,mid+1,r,st,en);
s[k]=merge(s[k<<1],s[k<<1|1]);
}
int sufmx(int x){
res={0,-INF};
for (;x;x=fa[top[x]])
query(1,1,n,in[top[x]],in[x]);
return res.mx;
}
int main(){
// freopen("in.txt","r",stdin);
int Q;
scanf("%d%d",&n,&Q);
for (int i=2;i<=n;++i){
scanf("%d",&fa[i]);
e[ne]={i,last[fa[i]]};
last[fa[i]]=e+ne++;
}
dfs1(1),dfs2(1,1);
init(1,1,n);
while (Q--){
int op,x;
scanf("%d%d",&op,&x);
if (op==1){
add(1,1,n,in[x],1);
}
else if (op==2){
int tmp=sufmx(x);
add(1,1,n,in[x],-tmp-1);
if (in[x]<out[x])
clear(1,1,n,in[x]+1,out[x]);
}
else{
int tmp=sufmx(x);
if (tmp>=0)
printf("black\n");
else
printf("white\n");
}
}
return 0;
}