CF1017G The Tree

题面

英文题面

题意:给定一棵树,维护以下3个操作:

  • 1 (x)表示如果节点(x)为白色,则将其染黑。否则对这个节点的所有儿子递归进行相同操作
  • 2 (x)表示将以节点(x)为root的子树染白。
  • 3 (x)表示查询节点(x)的颜色。

(n,q leq 10^5)

题解:考虑一种优雅的暴力------将所有询问分块。真是涨姿势了

由于所有操作都是针对单点的,我们可以在一个块的操作中只考虑这些询问涉及到的点,这样复杂度就降到了块长级别。然后做完后再(O(n))的考虑对原树中其他节点的影响。将块长设为(sqrt q),那么总复杂度就是(O(nsqrt n))的。

具体来说,我们先建出虚树,注意对每条边存一下边长和这条边上黑点的个数。然后对于1操作,直接暴力做就行,如果当前这条边上所有点都是黑的,就往下递归就行。对于2操作,暴力清空即可。3操作就直接输出,没啥好说的。

在还原这些操作对原树的节点的影响时,我们需要在上述操作中对虚树上的每个点记录两个值:(cnt_i,sn_i)分别表示当前节点1操作做了几次对它有影响,当前节点在这些操作中是否是2操作的点的子树里的一个点。DFS一遍就行了。

还有一种树剖的做法,大概是考虑每个(x)的祖先(y)对它能否造成贡献,把式子搞出来,然后提取出只与(y)相关的部分,用线段树维护即可。注意2操作时不仅要将子树清空,还要考虑祖先节点不能对其造成贡献。时间复杂度是俩log。

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
	res=0;register D g=1;register char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')g=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		res=(res<<3)+(res<<1)+(ch^48);
		ch=getchar();
	}
	res*=g;
}
int n,m,fa[101000],t[101000],v[101000],dfn[101000],dep[101000],siz[101000],id[101000],_tot,lg[202000],xu[202000],f[202000][20],cnt;
int len,b[101000],sum,ori[101000],clr[101000],sn[101000],ct[101000];
inline bool bbb(int x,int y){return dfn[x]<dfn[y];}
IN ckmin(int x,int y){return dep[x]<dep[y]?x:y;}
I print(int x){
	if(x)puts("black");
	else puts("white");
}
IN ques_lca(int x,int y){
	x=id[x];y=id[y];if(x>y)swap(x,y);
	re len=lg[y-x+1];return ckmin(f[x][len],f[y-(1<<len)+1][len]);
}
IN getit(int x,int tar){
	re res=0;
	while(x^tar)res+=clr[x],x=fa[x];
//	cout<<x<<" "<<tar<<endl,STS;
	return res;
}

namespace VT{
	struct E{
		int to,nt,s,v;
		E(int _to=0,int _nt=0,int _s=0,int _v=0){to=_to;nt=_nt;s=_s;v=_v;}
	}e[202000];
	#define T e[k].to
	int st[101000],q;
	int head[101000],tot;
	int a[101000],vis[101000],N;
	int c[101000],num,las;
	I add(int x,int y){
//		cout<<"A"<<x<<" "<<y<<endl;
		re s=dep[y]-dep[x]-1,v=getit(fa[y],x);
		e[++tot].to=y;e[tot].nt=head[x];head[x]=tot;e[tot].s=s;e[tot].v=v;
	}
	I insert(int x){
		if(!q)return st[q=1]=x,void();
		re lca=ques_lca(st[q],x);
//		cout<<"L"<<lca<<endl;
		if(lca==st[q])return st[++q]=x,void();
		while(dfn[lca]<dfn[st[q-1]])add(st[q-1],st[q]),q--;
//		cout<<"#";
		if(st[q-1]==lca)return add(st[q-1],st[q]),q--,st[++q]=x,void();
		add(lca,st[q]),q--,st[++q]=lca,st[++q]=x,vis[lca]=1;
	}
	I build(){
		tot=q=0;
		if(!vis[1])vis[1]=1,a[++N]=1;
		sort(a+1,a+1+N,bbb);
//		F(i,1,N)cout<<a[i]<<" ";cout<<endl;
		F(i,1,N)insert(a[i]);
//		cout<<"!";cout<<endl;
		while(q>1)add(st[q-1],st[q]),q--;
		F(i,1,n)ori[i]=clr[i];
	}	
	I sign(int x){
//		cout<<"%"<<x<<endl;
		if(!clr[x])return clr[x]=1,void();
		ct[x]++;
		for(re k=head[x];k!=-1;k=e[k].nt){
			if(e[k].v==e[k].s)sign(T);
			else e[k].v++;
		}
	}
	I fill(int x){
		clr[x]=ct[x]=0;sn[x]=1;
		for(re k=head[x];k!=-1;k=e[k].nt)e[k].v=0,fill(T);
	}
	I split(int x,int y){
		num=dep[y]-dep[x]-1;y=fa[y];
		FOR(i,num,1)c[i]=y,y=fa[y];
	}
	
	I clear(){
		F(i,1,n)head[i]=-1,sn[i]=vis[i]=ct[i]=0;
		N=tot=0;
	}
};
vector<int>e[101000];
I D_1(int x,int depth){
	dfn[x]=++_tot;xu[++cnt]=x;id[x]=cnt;siz[x]=1;dep[x]=depth;
//	cout<<x<<" ";
	for(auto d:e[x]){
		D_1(d,depth+1);siz[x]+=siz[d];xu[++cnt]=x;
	}
}
I reform(int x,int S){
//	cout<<"$"<<x<<" "<<sum+ct[x]<<endl;
	if(VT::vis[x])S=ct[x];
	else{
		if(sn[x])clr[x]=0;
		if(!clr[x]&&S)S--,clr[x]=1;
	}
		/*if(sn[x]){
			for(re k=head[x];k!=-1;k=e[k].nt){
//				split(x,T);
//				F(i,1,e[k].v)clr[c[i]]=1;
//				F(i,e[k].v+1,num)clr[c[i]]=0;
				sn[T]=1;reform(T);
			}
		}
		else{
			for(re k=head[x];k!=-1;k=e[k].nt){
//				split(x,T);las=getit(fa[T],x);
//				for(re i=1,j=1;i<=num&&j+las<=e[k].v;i++){
//					if(!clr[c[i]])clr[c[i]]=1,j++;
//				}
				reform(T);
			}	
		}*/
	for(auto d:e[x]){
		sn[d]|=sn[x];reform(d,S);
	}
}
I solve(int l,int r){
//	cout<<"!"<<l<<" "<<r<<endl;
	F(i,l,r)if(!VT::vis[v[i]])VT::vis[v[i]]=1,VT::a[++VT::N]=v[i];
	VT::build();
//	cout<<"F"<<endl;
	F(i,l,r){
		if(t[i]==1){
//			ct[v[i]]++;
			VT::sign(v[i]);
		}
		if(t[i]==2)VT::fill(v[i]);
		if(t[i]==3)print(clr[v[i]]);
	}
//	cout<<"@";
//	F(i,1,n)cout<<ct[i]<<" ";cout<<endl;
//	F(i,1,n)cout<<VT::vis[i];cout<<endl;
//	F(i,1,n)clr[i]=ori[i];
	reform(1,0);VT::clear();
//	F(i,1,n)cout<<clr[i];cout<<endl;
//	cout<<"#"<<endl;
}
int main(){
	read(n);read(m);C(VT::head,-1);
	F(i,2,n)read(fa[i]),e[fa[i]].emplace_back(i);
	F(i,1,m)read(t[i]),read(v[i]);
	len=ceil(sqrt(m)+0.5);F(i,1,m)b[i]=((i-1)/len)+1;sum=b[m];
	D_1(1,0);
	//cout<<endl;
	lg[0]=-1;F(i,1,cnt)f[i][0]=xu[i],lg[i]=lg[i>>1]+1;
	F(j,1,lg[cnt])F(i,1,cnt-(1<<j)+1)f[i][j]=ckmin(f[i][j-1],f[i+(1<<(j-1))][j-1]);
	F(i,1,sum)solve((i-1)*len+1,min(m,i*len));	
	return 0;
}
/*
8 10
1 2 1 2 5 4 5
1 2
3 2
3 1
1 1
1 1
3 5
3 7
3 4
2 2
3 5
*/
原文地址:https://www.cnblogs.com/Purple-wzy/p/13297048.html