Linkernode
作法:树链剖分+线段树c++
首先\(O(n^2)\)的暴力仍是挺好想的,就很少阐述了。ui
而后看没有2操做的该怎么写。spa
当没有2操做的时候,咱们能够经过一种特殊的形式来记录点的染色:经过给这个点加权值。debug
假设x是y的祖先,若x能够影响到y的话,不难发现,须要知足的性质就是 \(x\to y\ \text{这一段路上的总权值}>=dep[x]-dep[y]+1\)code
记录这一段路上的总权值为\(dis\),移项获得 \(dis+dep[x]>=dep[y]+1\)get
利用线段树维护\(dis+dep[x]\),而后对于向上跳的过程直接树链剖分向上跳。it
也就是说经过树链剖分+线段树就能写出来。这里代码就不放出来了。class
再看若是有了2操做咱们该如何写。bug
首先把这一整课子树清空是确定要的。
而后就看若是祖先的\(dis\)的影响到了下面的节点该如何操做。
再来看看刚刚的式子 : \(dis+dep[x]>=dep[y]+1\)
咱们发现能够找到x的祖先的\(dis+dep\)的最大值(其实就是再往上跳一遍),也会影响到他的子树(虽说子树的每一个点的\(dis+dep\)已经清零了,可是仍是能够从上面转移下来)
因而咱们找到这个值之后,再让x的权值减去它就行了(至关于差分)
//代码很丑,勿喷 #include<bits/stdc++.h> #define re register #define rep(i,a,b) for(re int i=a,i##end=b; i<=i##end; i++) #define drep(i,a,b) for(re int i=a,i##end=b; i>=i##end; i--) #define repp(i,a,b) for(re int i=a,i##end=b; i<i##end; i++) #define drepp(i,a,b) for(re int i=a,i##end=b; i>i##end; i--) #define Erep(i,x) for(re int i=head[x]; i; i=Edge[i].nxt) #define lowbit(x) ((x)&-(x)) #define debug(x) cerr<<#x<<" = "<<x<<endl #define ms(x,a) memset(x,a,sizeof x) #define PII pair<int,int> #define PLL pair<ll,ll> #define fi first #define se second #define coint const int #define coll const ll #define CM cerr<<(&S2-&S1)/1024./1024.<<"MB"<<endl typedef long long ll; using namespace std; template<class T>inline T rd(){ static char ch;static bool neg;static T x; for(ch=0, neg=0; ch>'9'||ch<'0'; neg|=(ch=='-'),ch=getchar()); for(x=0; ch>='0'&&ch<='9'; x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar()); return neg?-x:x; } template<class T>inline T Max(const T &x, const T &y) { return x>y?x:y; } template<class T>inline T Min(const T &x, const T &y) { return x<y?x:y; } coint N=100000+5,M=200000+5; struct edge{ int to,nxt; }Edge[N<<1]; int head[N],tcnt; inline void AddEdge(coint u, coint v){ Edge[++tcnt]=(edge)<%v,head[u]%>; head[u]=tcnt; return; } struct Ask{ int opt,x; inline void read() { opt=rd<int>(); x=rd<int>(); return; } }ask[M]; int n,m; int dep[N],f[N],sz[N],son[N],top[N],L[N],R[N],ID[N],dfn; void pre_dfs(coint x, coint fa){ int &SZ=sz[x],&SON=son[x]; SZ=1; Erep(i,x){ int y=Edge[i].to; if(y==fa) continue; dep[y]=dep[x]+1; f[y]=x; pre_dfs(y,x); SZ+=sz[y]; SON=(sz[SON]<sz[y]?y:SON); } return; } void dfs_top(coint x, coint fa, coint tp){ top[x]=tp; L[x]=++dfn; ID[dfn]=x; coint &SON=son[x]; if(SON) dfs_top(SON,x,tp); Erep(i,x){ int y=Edge[i].to; if(y==fa || y==SON) continue; dfs_top(y,x,y); } R[x]=dfn; return; } struct node{ int sum,mx; friend node operator + (const node &x, const node &y){ return (node)<%x.sum+y.sum,Max(x.mx+y.sum,y.mx)%>; } }; struct Segment_Tree{ node sum[N<<2]; int lazy[N<<2]; inline void Up(coint p){ coint ls=p<<1,rs=ls|1; sum[p]=sum[ls]+sum[rs]; return; } inline void Down(coint p){ int &x=lazy[p]; if(!x) return; coint ls=p<<1,rs=ls|1; lazy[ls]=lazy[rs]=1; sum[ls]=sum[rs]=(node)<%0,0%>; x=0; return; } void Build(coint p, coint l, coint r){ sum[p]=(node)<%0,0%>; lazy[p]=0; if(l==r) return; coint mid=(l+r)>>1,ls=p<<1,rs=ls|1; Build(ls,l,mid); Build(rs,mid+1,r); return; } void Upd1(coint p, coint l, coint r, coint L, coint R){ if(l==L && r==R){ sum[p]=(node)<%0,0%>; lazy[p]=1; return; } Down(p); coint mid=(l+r)>>1,ls=p<<1,rs=ls|1; if(R<=mid) Upd1(ls,l,mid,L,R); else if(L>mid) Upd1(rs,mid+1,r,L,R); else Upd1(ls,l,mid,L,mid),Upd1(rs,mid+1,r,mid+1,R); Up(p); return; } void Upd2(coint p, coint l, coint r, coint x, coint val){ if(l==r){ sum[p]=(node)<%val,dep[ID[l]]+val%>; return; } Down(p); coint mid=(l+r)>>1,ls=p<<1,rs=ls|1; if(x<=mid) Upd2(ls,l,mid,x,val); else Upd2(rs,mid+1,r,x,val); Up(p); return; } node Que(coint p, coint l, coint r, coint L, coint R){ if(l==L && r==R) return sum[p]; Down(p); coint mid=(l+r)>>1,ls=p<<1,rs=ls|1; if(R<=mid) return Que(ls,l,mid,L,R); if(L>mid) return Que(rs,mid+1,r,L,R); return Que(ls,l,mid,L,mid)+Que(rs,mid+1,r,mid+1,R); } }sgtr; inline int Get_Max(int x){ node res=(node)<%0,0%>; int tpx=top[x]; while(x){ res=sgtr.Que(1,1,n,L[tpx],L[x])+res; x=f[tpx]; tpx=top[x]; } return res.mx; } inline void solve(){ pre_dfs(1,0); dfs_top(1,0,1); rep(i,1,m){ coint opt=(ask[i].opt),x=ask[i].x; switch(opt){ case 1:{ sgtr.Upd2(1,1,n,L[x],sgtr.Que(1,1,n,L[x],L[x]).sum+1); break; } case 2:{ sgtr.Upd1(1,1,n,L[x],R[x]); int tmp=Get_Max(x); if(tmp>=dep[x]+1) sgtr.Upd2(1,1,n,L[x],dep[x]-tmp); break; } default:{ puts(Get_Max(x)>=dep[x]+1?"black":"white"); break; } } } return; } int main(){ n=rd<int>(),m=rd<int>(); rep(i,2,n){ int x=rd<int>(); AddEdge(x,i); AddEdge(i,x); } rep(i,1,m) ask[i].read(); solve(); return 0; }