zoukankan      html  css  js  c++  java
  • 「雅礼集训 2018 Day2」农民

    传送门

    Description 

    「搞 OI 不如种田。」

    小 D 在家种了一棵二叉树,第 ii 个结点的权值为 (a_i)

    小 D 为自己种的树买了肥料,每天给树施肥。

    可是几天后,小 D 却发现树上有几个结点枯死了,他这才发现,自己买的肥料是二叉搜索树专用版。

    二叉搜索树是一种二叉树,满足每个结点的权值大于左子树内所有点的权值,小于右子树内所有点的权值。

    二叉搜索树专用版肥料是这么工作的:首先,假设所有节点权值互不相同(小 D 的二叉树可能不满足),每种权值对应一种肥料,所有肥料会从根进入树中,如果一种肥料对应的权值等于当前结点权值,这种肥料会被当前结点完全吸收,否则若肥料对应的权值小于当前结点权值,肥料会流向左子树,否则流向右子树,如果流向的子树为空,肥料只好流失蒸发了。显然,如果树是二叉搜索树,所有节点都能吸收到肥料。

    小 D 觉得自己还能抢救一下,他会进行若干次操作,每次操作修改一个点的权值或者翻转一个子树(子树内所有节点左右儿子互换)。在操作过程中,他有时会想知道一个点当前是否能吸收到肥料,以决定之后如何操作,请你帮帮可怜的小 D 吧。

    Solution

    我们把每条边当成是一个元素,这个元素是一个可行的区间

    对于一个点,它能够可行当且仅当它属于它到根节点路径上所有元素区间的并

    可以求出dfs序后用线段树维护

    对于取反操作,我们同时维护一下线段树上每个元素取反后的区间,修改时直接打标记就行


    Code 

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    const int MN=1e6+5,inf=1<<30;
    int n,m,a[MN],c[MN][2],dfn[MN],fdfn[MN],top[MN],siz[MN],mx[MN],fa[MN],R[MN];
    bool ch[MN];
    inline void dfs1(int x,int f)
    {
    	siz[x]=1;fa[x]=f;ch[x]=c[f][1]==x;
    	if(c[x][0]) dfs1(c[x][0],x);
    	if(c[x][1]) dfs1(c[x][1],x);
    	siz[x]+=siz[c[x][0]]+siz[c[x][1]];
    	mx[x]=siz[c[x][0]]>siz[c[x][1]]?0:1;
    }
    inline void dfs2(int x,int f,int tp)
    {
    	static int ind=0;
    	dfn[x]=++ind;top[x]=tp;fdfn[ind]=x;
    	if(c[x][mx[x]]) dfs2(c[x][mx[x]],x,tp);
    	if(c[x][mx[x]^1]) dfs2(c[x][mx[x]^1],x,c[x][mx[x]^1]);
    	R[x]=ind;
    }
    class Test
    {
    	bool rev[MN<<2],son[MN<<1];
    	struct F{int l,r,_l,_r;}T[MN<<2];
    	F merge(F o,F oo){return (F){max(o.l,oo.l),min(o.r,oo.r),max(o._l,oo._l),min(o._r,oo._r)};}
    	bool P(int x,F y){return x>=y.l&&x<=y.r;}
    	void Rev(int x){rev[x]^=1;son[x]^=1;std::swap(T[x].l,T[x]._l);std::swap(T[x].r,T[x]._r);}
    	void pushdown(int x){if(!rev[x])return;Rev(x<<1);Rev(x<<1|1);rev[x]=0;}
    	#define L fdfn[l]
    	void update(int x,int l,int r,int u)
    	{
    		if(l==r)
    		{
    			if(son[x]) T[x].l=a[fa[L]]+1,T[x].r=inf,T[x]._l=1,T[x]._r=a[fa[L]]-1;
    			else T[x]._l=a[fa[L]]+1,T[x]._r=inf,T[x].l=1,T[x].r=a[fa[L]]-1;
    			return;
    		}
    		int mid=(l+r)>>1;pushdown(x);
    		if(u<=mid) update(x<<1,l,mid,u);
    		else update(x<<1|1,mid+1,r,u);
    		T[x]=merge(T[x<<1],T[x<<1|1]);
    	}
    	void re(int x,int l,int r,int a,int b)
    	{
    		if(a>b) return;if(l==a&&r==b){Rev(x);return;}
    		int mid=(l+r)>>1;pushdown(x);
    		if(b<=mid) re(x<<1,l,mid,a,b);
    		else if(a>mid) re(x<<1|1,mid+1,r,a,b);
    		else re(x<<1,l,mid,a,mid),re(x<<1|1,mid+1,r,mid+1,b);
    		T[x]=merge(T[x<<1],T[x<<1|1]);
    	}
    	F Query(int x,int l,int r,int a,int b)
    	{
    		if(a==l&&b==r) return T[x];
    		int mid=(l+r)>>1;pushdown(x);
    		if(b<=mid) return Query(x<<1,l,mid,a,b);
    		else if(a>mid) return Query(x<<1|1,mid+1,r,a,b);
    		return merge(Query(x<<1,l,mid,a,mid),Query(x<<1|1,mid+1,r,mid+1,b));
    	}
    	public:
    		void Build(int x,int l,int r)
    		{
    			if(l==r)
    			{
    				son[x]=ch[L];
    				if(L==1) T[x].l=T[x]._l=1,T[x].r=T[x]._r=inf;
    				else if(ch[L]) T[x].l=a[fa[L]]+1,T[x].r=inf,T[x]._l=1,T[x]._r=a[fa[L]]-1;
    				else T[x]._l=a[fa[L]]+1,T[x]._r=inf,T[x].l=1,T[x].r=a[fa[L]]-1;
    				return;
    			}
    			int mid=(l+r)>>1;
    			Build(x<<1,l,mid);Build(x<<1|1,mid+1,r);
    			T[x]=merge(T[x<<1],T[x<<1|1]);
    		}
    		void upd(int x,int y)
    		{
    			a[x]=y;
    			if(c[x][0]) update(1,1,n,dfn[c[x][0]]);
    			if(c[x][1]) update(1,1,n,dfn[c[x][1]]);
    		}
    		bool query(int x)
    		{
    			int o=a[x];
    			F ans=(F){1,inf,1,inf};
    			while(x&&ans.l<=ans.r) ans=merge(ans,Query(1,1,n,dfn[top[x]],dfn[x])),x=fa[top[x]];
    			return P(o,ans);
    		}
    		void reve(int x){re(1,1,n,dfn[x]+1,R[x]);}
    	#undef L
    }T;
    int main()
    {
    	n=read();m=read();register int i,opt,x;
    	for(i=1;i<=n;++i) a[i]=read(),c[i][0]=read(),c[i][1]=read();
    	dfs1(1,0);dfs2(1,0,1);T.Build(1,1,n);
    	while(m--)
    	{
    		opt=read();x=read();
    		if(opt==1) T.upd(x,read());
    		if(opt==2) T.reve(x);
    		if(opt==3) puts(T.query(x)?"YES":"NO");
    	}
    	return 0;
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    借助NetFlow Analyzer的IPAM SPM插件,轻松实现IP和交换机端口管理
    补丁日微软修复了129个漏洞,学习补丁管理最佳实践
    如何通过组策略映射驱动器?
    如何预防磁盘使用率过高?
    ITIL是什么意思?
    Applications Manager—打造最佳云监控策略
    Microsoft 365独家安全解决方案
    怎么让Chrome支持小于12px 的文字?
    vue Router的使用
    vue项目中随机生成验证码
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/farmer_loj6498.html
Copyright © 2011-2022 走看看