CF1017G 【The Tree】

Linker

做法:树链剖分+线段树

首先(O(n^2))的暴力还是挺好想的,就不多阐述了。

然后看没有2操作的该怎么写。

当没有2操作的时候,我们可以通过一种特殊的形式来记录点的染色:通过给这个点加权值。

假设x是y的祖先,若x可以影响到y的话,不难发现,需要满足的性质就是 (x o y ext{这一段路上的总权值}>=dep[x]-dep[y]+1)

记录这一段路上的总权值为(dis),移项得到 (dis+dep[x]>=dep[y]+1)

利用线段树维护(dis+dep[x]),然后对于向上跳的过程直接树链剖分向上跳。

也就是说通过树链剖分+线段树就能写出来。这里代码就不放出来了。

再看如果有了2操作我们该如何写。

首先把这一整课子树清空是肯定要的。

然后就看如果祖先的(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;
}

原文地址:https://www.cnblogs.com/ppp204-is-a-VC/p/11836635.html