• CF1017G The Tree(统计+树剖)


    CF1017G The Tree

    给定一棵树,维护以下 \(3\) 个操作:

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

    \(n,q\le 10^5\)

    \(\bigstar\texttt{Hint-1}\):如果真的向题目所说的去给每个点染色,将非常难维护。如果发现题目中信息混乱不妨向统计学方向考虑,我们记下这个 \(x\) 向下多少深度被染色,在每个点上根据它与根的路径查询答案。

    如果没有 \(2\) 操作,我们在每个点上记录在它身上加了几次,那么查询时询问根到它的路径是否存在一段后缀和等于这段后缀的长度。不妨用一个更优美的解决方法,将每个点初始值设为 \(-1\),那么查询是否有一段后缀和 \(\ge 0\)

    \(\bigstar\texttt{Hint-2}\):那么 \(2\) 操作呢?首先将子树内的值都清空,权值赋为初值 \(-1\);并且需要去掉上面的点对子树内的贡献,就在 \(x\) 处加上从上面下来的影响深度(到 \(x\) 的最大后缀和)即可。

    也就是在 \(x\) 处减去 \(query(x)+1\)

    另一种操作是离线后处理,但比较麻烦。

    剩下的就是树剖入门题了,没什么好康的。

    #define Maxn 100005
    int n,q,tot,Time;
    int hea[Maxn],nex[Maxn<<1],ver[Maxn<<1];
    int dfnl[Maxn],dfnr[Maxn],siz[Maxn],dep[Maxn],bigson[Maxn],tp[Maxn],fa[Maxn];
    inline void addedge(int x,int y){ ver[++tot]=y,nex[tot]=hea[x],hea[x]=tot; }
    /************************** 线段树 + 树剖 *******************************/
    struct TREE
    {
    	ll sum,maxlast; bool laztag;
    	TREE(){ sum=maxlast=-1; laztag=false; }
    	inline void Imply(ll x) { laztag=true,sum=-x,maxlast=-1; }
    	inline void Push(ll val) { sum+=val,maxlast=sum; }
    };
    TREE tree[Maxn<<2];
    inline TREE merge(TREE L,TREE R)
    {
    	TREE ret;
    	ret.sum=L.sum+R.sum;
    	ret.maxlast=max(R.maxlast,L.maxlast+R.sum);
    	return ret;
    }
    inline void pushdown(int p,int nl,int nr)
    {
    	if(tree[p].laztag)
    	{
    		int mid=(nl+nr)>>1;
    		tree[p<<1].Imply(mid-nl+1);
    		tree[p<<1|1].Imply(nr-mid);
    		tree[p].laztag=false;
    	}
    }
    void add(int p,int nl,int nr,int x,ll val)
    {
    	if(nl==nr) { tree[p].Push(val); return; }
    	int mid=(nl+nr)>>1; pushdown(p,nl,nr);
    	if(mid>=x) add(p<<1,nl,mid,x,val);
    	else add(p<<1|1,mid+1,nr,x,val);
    	tree[p]=merge(tree[p<<1],tree[p<<1|1]);
    }
    void build(int p,int nl,int nr)
    {
    	if(nl==nr) return;
    	int mid=(nl+nr)>>1;
    	build(p<<1,nl,mid),build(p<<1|1,mid+1,nr);
    	tree[p]=merge(tree[p<<1],tree[p<<1|1]);
    }
    ll query(int p,int nl,int nr,int l,int r)
    {
    	if(nl>=l && nr<=r) return tree[p].sum;
    	int mid=(nl+nr)>>1; ll ret=0;
    	pushdown(p,nl,nr);
    	if(mid>=l) ret+=query(p<<1,nl,mid,l,r);
    	if(mid<r) ret+=query(p<<1|1,mid+1,nr,l,r);
    	return ret;
    }
    void change(int p,int nl,int nr,int l,int r)
    {
    	if(nl>=l && nr<=r) { tree[p].Imply(nr-nl+1); return; }
    	int mid=(nl+nr)>>1; pushdown(p,nl,nr);
    	if(mid>=l) change(p<<1,nl,mid,l,r);
    	if(mid<r) change(p<<1|1,mid+1,nr,l,r);
    	tree[p]=merge(tree[p<<1],tree[p<<1|1]);
    }
    TREE color(int p,int nl,int nr,int l,int r)
    {
    	if(nl>=l && nr<=r) return tree[p];
    	int mid=(nl+nr)>>1; pushdown(p,nl,nr);
    	if(mid>=l && mid<r)
    		return merge(color(p<<1,nl,mid,l,r),color(p<<1|1,mid+1,nr,l,r));
    	else if(mid>=l) return color(p<<1,nl,mid,l,r);
    	else return color(p<<1|1,mid+1,nr,l,r);
    }
    inline ll colorpath(int x)
    {
    	TREE ret; bool exist=false;
    	while(tp[x]!=1)
    	{
    		if(!exist) ret=color(1,1,n,dfnl[tp[x]],dfnl[x]),exist=true;
    		else ret=merge(color(1,1,n,dfnl[tp[x]],dfnl[x]),ret);
    		x=fa[tp[x]];
    	}
    	if(!exist) ret=color(1,1,n,1,dfnl[x]),exist=true;
    	else ret=merge(color(1,1,n,1,dfnl[x]),ret);
    	return ret.maxlast;
    }
    void dfs1(int x)
    {
    	siz[x]=1;
    	for(int i=hea[x];i;i=nex[i])
    	{
    		dep[ver[i]]=dep[x]+1,fa[ver[i]]=x,dfs1(ver[i]);
    		if(siz[ver[i]]>siz[bigson[x]]) bigson[x]=ver[i];
    		siz[x]+=siz[ver[i]];
    	}
    }
    void dfs2(int x,int T)
    {
    	tp[x]=T,dfnl[x]=++Time;
    	if(bigson[x]) dfs2(bigson[x],T);
    	for(int i=hea[x];i;i=nex[i]) if(ver[i]!=bigson[x]) dfs2(ver[i],ver[i]);
    	dfnr[x]=Time;
    }
    /**********************************************************************/
    int main()
    {
    	n=rd(),q=rd();
    	for(int i=2,F;i<=n;i++) F=rd(),addedge(F,i);
    	dep[1]=1,dfs1(1),dfs2(1,1);
    	build(1,1,n); ll tmp;
    	for(int i=1,opt,x;i<=q;i++)
    	{
    		opt=rd(),x=rd();
    		if(opt==1) add(1,1,n,dfnl[x],1);
    		else if(opt==2)
    		{
    			tmp=colorpath(x),add(1,1,n,dfnl[x],-tmp-1);
    			if(dfnl[x]<dfnr[x]) change(1,1,n,dfnl[x]+1,dfnr[x]);
    		}
    		else printf((colorpath(x)>=0)?"black\n":"white\n");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Pulp之四:其它应用样例(1)-一般的整数规划问题 (设置目标约束函数)
    Pulp之三:官网上的应用样例(4)-Blending Problem (混合问题)
    Pulp之三:官网上的应用样例(3)-Sudoku Problem by LP (数独问题)
    Pulp之三:官网上的应用样例(2)-A Set Partitioning Problem (集合划分问题)
    list转换dict的方式以及zip的用法
    Pulp之三:官网上的应用样例(1)-The_Whiskas_Problem (猫粮配料比例问题)
    Pulp之二:Pulp中几个重要的概念
    一个简单有趣的题(4个变量找出取走的数)
    Java之父 James Gosling 发表博文 《Too Soon》纪念乔布斯。
    第01课 OpenGL窗口(1)
  • 原文地址:https://www.cnblogs.com/EricQian/p/16830226.html
Copyright © 2020-2023  润新知