题意:
给一颗一开始全是白点的树,支持三个操作:
1:将某一个点改成白点,假如已经是白点,则对儿子进行该操作。
2:将一颗子树改成白色
3:询问某个点的颜色
题解:
显然是在要操作的点上打上标记。
关键是要设计一种有用的标记,比赛时sb,没有想到可以用后缀和……
一开始整棵树都是-1,对于一操作,就在该点上+1,那么一个点上是黑点当前仅当它到根的路径的最大后缀和>=0。
2操作等于将一棵子树标为-1,但是这样也不能保证子树中的点的最大后缀和=-1,所以要在该子树的根将子树外的影响消掉。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=1<<28;
struct node{int c,max;};
struct trnode{
int fa,dep,tot,top,son,lc,rc;
bool u;node c;
trnode() {u=false;}
}tr[200010];int tot=0;
int ys[100010],la[100010],z=0;
struct Node{
int y,next;
}a[200010];int len=0,last[100010];
int n,q;
void ins(int x,int y)
{
a[++len].y=y;
a[len].next=last[x];last[x]=len;
}
void pre_node(int x,int fa)
{
tr[x].fa=fa;tr[x].dep=tr[fa].dep+1;tr[x].tot=1;
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
pre_node(y,x);tr[x].tot+=tr[y].tot;
if(tr[tr[x].son].tot<tr[y].tot) tr[x].son=y;
}
}
void pre_edge(int x,int top)
{
tr[x].top=top;ys[x]=la[x]=++z;
if(tr[x].son) pre_edge(tr[x].son,top),la[x]=la[tr[x].son];
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==tr[x].fa||y==tr[x].son) continue;
pre_edge(y,y);la[x]=la[y];
}
}
node update(node lc,node rc)
{
node ans;ans.c=lc.c+rc.c;
ans.max=max(rc.max,lc.max+rc.c);
return ans;
}
int bt(int l,int r)
{
int x=++tot;
if(l!=r)
{
int mid=(l+r)/2;
tr[x].lc=bt(l,mid);
tr[x].rc=bt(mid+1,r);
tr[x].c=update(tr[tr[x].lc].c,tr[tr[x].rc].c);
}
else tr[x].c.c=tr[x].c.max=-1;
return x;
}
void pushdown(int x,int l,int r)
{
int lc=tr[x].lc,rc=tr[x].rc,mid=(l+r)/2;
tr[lc].c.c=-(mid-l+1);tr[lc].c.max=-1;tr[lc].u=true;
tr[rc].c.c=-(r-mid);tr[rc].c.max=-1;tr[rc].u=true;
tr[x].u=false;
}
void change(int x,int l,int r,int fl,int fr,int c)
{
if(l==fl&&r==fr)
{
if(c==inf) tr[x].c.c=-(r-l+1),tr[x].c.max=-1,tr[x].u=true;
else tr[x].c.c+=c,tr[x].c.max+=c;
return;
}
if(tr[x].u) pushdown(x,l,r);
int mid=(l+r)/2;
if(fr<=mid) change(tr[x].lc,l,mid,fl,fr,c);
else if(fl>mid) change(tr[x].rc,mid+1,r,fl,fr,c);
else change(tr[x].lc,l,mid,fl,mid,c),change(tr[x].rc,mid+1,r,mid+1,fr,c);
tr[x].c=update(tr[tr[x].lc].c,tr[tr[x].rc].c);
}
node findans(int x,int l,int r,int fl,int fr)
{
if(l==fl&&r==fr) return tr[x].c;
if(tr[x].u) pushdown(x,l,r);
int mid=(l+r)/2;
if(fr<=mid) return findans(tr[x].lc,l,mid,fl,fr);
if(fl>mid) return findans(tr[x].rc,mid+1,r,fl,fr);
return update(findans(tr[x].lc,l,mid,fl,mid),findans(tr[x].rc,mid+1,r,mid+1,fr));
}
int solve(int x)
{
node ans;ans.c=0;ans.max=-inf;
int tx=tr[x].top;
while(tx!=1)
{
ans=update(findans(1,1,n,ys[tx],ys[x]),ans);
x=tr[tx].fa;tx=tr[x].top;
}
node k=findans(1,1,n,ys[1],ys[x]);
//printf("solve:%d %d %d %d\n",tx,x,k.c,k.max);
ans=update(k,ans);
//printf("%d %d\n",ans.c,ans.max);
return ans.max;
}
int main()
{
scanf("%d %d",&n,&q);
bt(1,n);
for(int i=2;i<=n;i++)
{
int x;scanf("%d",&x);
ins(x,i);ins(i,x);
}
pre_node(1,0);pre_edge(1,1);
//for(int i=1;i<=n;i++) printf("%d %d\n",ys[i],la[i]);
while(q--)
{
int op,x;scanf("%d %d",&op,&x);
if(op==1) change(1,1,n,ys[x],ys[x],1);
if(op==2)
{
change(1,1,n,ys[x],la[x],inf);
int k=solve(x);
if(k>-1) change(1,1,n,ys[x],ys[x],-(k+1));
}
if(op==3)
{
int k=solve(x);
if(k>-1) printf("black\n");
else printf("white\n");
}
//for(int i=1;i<=n;i++) printf("%d ",findans(1,1,n,ys[i],ys[i]).max);printf("\n");
}
}