• 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;
    }
    
    
  • 相关阅读:
    CSS 单行超出隐藏
    python开发学习day12 (函数参数;函数对象)
    作业day11
    python开发学习day11 (函数; 返回值 ; 形参与实参 )
    python开发学习day10 (文件指针; 文本修改)
    作业day09
    python开发学习day09 (with上下文处理; b模式; +模式; 文件操作)
    作业day08
    python开发学习day08 (集合; 文件操作)
    作业day07
  • 原文地址:https://www.cnblogs.com/ppp204-is-a-VC/p/11836635.html
Copyright © 2020-2023  润新知