码迷,mamicode.com
首页 > 其他好文 > 详细

CF1017G The Tree

时间:2020-11-10 11:13:14      阅读:6      评论:0      收藏:0      [点我收藏+]

标签:query   pac   init   white   连通   赋值   处理   接下来   The   

一棵树,每个点为黑点或白点。一开始全是白点。

支持维护三个操作: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;
}

CF1017G The Tree

标签:query   pac   init   white   连通   赋值   处理   接下来   The   

原文地址:https://www.cnblogs.com/jz-597/p/13950860.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!