zoukankan      html  css  js  c++  java
  • 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
    */
    
  • 相关阅读:
    JavaScript underscore
    JavaScript jQuery 事件、动画、扩展
    JavaScript jQuery 入门回顾
    JavaScript H5 Canvas
    JavaScript Ajax + Promise
    JavaScript 浏览器对象
    JavaScript 面向对象编程
    JavaScript 标准对象
    JavaScript 高阶函数 + generator生成器
    “耐撕”团队2016.04.12站立会议
  • 原文地址:https://www.cnblogs.com/Purple-wzy/p/13297048.html
Copyright © 2011-2022 走看看