zoukankan      html  css  js  c++  java
  • 【刷题】BZOJ 4817 [Sdoi2017]树点涂色

    Description

    Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路

    径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:

    1 x:

    把点x到根节点的路径上所有的点染上一种没有用过的新颜色。

    2 x y:

    求x到y的路径的权值。

    3 x y:

    在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。

    Bob一共会进行m次操作

    Input

    第一行两个数n,m。

    接下来n-1行,每行两个数a,b,表示a与b之间有一条边。

    接下来m行,表示操作,格式见题目描述

    1<=n,m<=100000

    Output

    每当出现2,3操作,输出一行。

    如果是2操作,输出一个数表示路径的权值

    如果是3操作,输出一个数表示权值的最大值

    Sample Input

    5 6
    1 2
    2 3
    3 4
    3 5
    2 4 5
    3 3
    1 4
    2 4 5
    1 5
    2 4 5

    Sample Output

    3
    4
    2
    2

    Solution

    这真的是一道数据结构神题
    一步一步来,我们先看如何求答案
    对于第2个询问,如果我们知道每个节点到根路径上的答案,那么就变成了经典的树上差分,(ans(u)+ans(v)-2*ans(lca_{u,v})+1)
    这里解释一下+1,这东西很妙啊。看修改操作,每次都是把一个点到根路径上的颜色都改成一种新的颜色,所以不可能存在 (u)(lca)(lca) 除外)的路径上与 (v)(lca)(lca) 除外)的路径上有相同的颜色,路径上也不可能出现颜色断层现象。所以只有两种情况:一是 (lca) 上的颜色不与任何它到 (u)(v) 路径上的颜色相同,这样减去后,因为 (lca) 上是一种新的颜色,所以要加1;二是 (lca) 上的颜色与它到 (u)(v) 的某一条路径上连着的一段颜色相同,这样减去之后这连着一段颜色相同的贡献多减了一次,所以还是要加1
    关键就是这个修改操作,很精髓,所以这样差分是正确的(可以自己手动画画)
    然后对于第3个询问,既然我们维护的就是 (ans(u))(ans(v)) ,那么就再找到它的 (lca) ,直接三次询问就出答案了
    再看第一个修改操作,这不很像LCT的access吗,那就用access维护
    而对于 (ans(u)) 答案的维护,因为又要维护点,又要维护子树,那就树剖后的线段树吧
    然后每次access的时候,如果断开了右儿子的链,那么右儿子与当前点的颜色就不一样了,所以要给右儿子所在的子树的答案加1;而新接的右子树因为从颜色不一样变成了颜色一样,所以要给新的右子树的答案减1
    数据结构啊,数据结构。。

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define ld long double
    const int MAXN=100000+10;
    int n,m,e,to[MAXN<<1],nex[MAXN<<1],beg[MAXN],srt[MAXN],end[MAXN],hson[MAXN],cnt,size[MAXN],fa[MAXN],dep[MAXN],iit[MAXN],top[MAXN];
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    #define Mid ((l+r)>>1)
    #define lson rt<<1,l,Mid
    #define rson rt<<1|1,Mid+1,r
    struct SEG{
    	int Mx[MAXN<<2],Ad[MAXN<<2];
    	inline void PushUp(int rt)
    	{
    		Mx[rt]=max(Mx[rt<<1],Mx[rt<<1|1]);
    	}
    	inline void PushDown(int rt)
    	{
    		Mx[rt<<1]+=Ad[rt];Mx[rt<<1|1]+=Ad[rt];
    		Ad[rt<<1]+=Ad[rt];Ad[rt<<1|1]+=Ad[rt];
    		Ad[rt]=0;
    	}
    	inline void Build(int rt,int l,int r)
    	{
    		if(l==r)Mx[rt]=iit[l];
    		else
    		{
    			Build(lson);Build(rson);
    			PushUp(rt);
    		}
    	}
    	inline void Update(int rt,int l,int r,int L,int R,int k)
    	{
    		if(L<=l&&r<=R)Mx[rt]+=k,Ad[rt]+=k;
    		else
    		{
    			PushDown(rt);
    			if(L<=Mid)Update(lson,L,R,k);
    			if(R>Mid)Update(rson,L,R,k);
    			PushUp(rt);
    		}
    	}
    	inline int QuerySm(int rt,int l,int r,int pos)
    	{
    		if(l==r&&r==pos)return Mx[rt];
    		else
    		{
    			PushDown(rt);
    			if(pos<=Mid)return QuerySm(lson,pos);
    			else return QuerySm(rson,pos);
    		}
    	}
    	inline int QueryMx(int rt,int l,int r,int L,int R)
    	{
    		if(L<=l&&r<=R)return Mx[rt];
    		else
    		{
    			PushDown(rt);
    			int res=0;
    			if(L<=Mid)chkmax(res,QueryMx(lson,L,R));
    			if(R>Mid)chkmax(res,QueryMx(rson,L,R));
    			return res;
    		}
    	}
    };
    SEG T1;
    #undef Mid
    #undef lson
    #undef rson
    #define lc(x) ch[(x)][0]
    #define rc(x) ch[(x)][1]
    struct LCT{
    	int ch[MAXN][2],fa[MAXN];
    	inline bool nroot(int x)
    	{
    		return lc(fa[x])==x||rc(fa[x])==x;
    	}
    	inline void rotate(int x)
    	{
    		int f=fa[x],p=fa[f],c=(rc(f)==x);
    		if(nroot(f))ch[p][rc(p)==f]=x;
    		fa[ch[f][c]=ch[x][c^1]]=f;
    		fa[ch[x][c^1]=f]=x;
    		fa[x]=p;
    	}
    	inline void splay(int x)
    	{
    		for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
    			if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x);
    	}
    	inline int findroot(int x)
    	{
    		while(lc(x))x=lc(x);
    		return x;
    	}
    	inline void access(int x)
    	{
    		for(register int y=0,rt;x;x=fa[y=x])
    		{
    			splay(x);
    			if(rc(x))rt=findroot(rc(x)),T1.Update(1,1,n,srt[rt],end[rt],1);
    			rc(x)=y;
    			if(rc(x))rt=findroot(rc(x)),T1.Update(1,1,n,srt[rt],end[rt],-1);
    		}
    	}
    };
    LCT T2;
    #undef lc
    #undef rc
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char c='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(c!='')putchar(c);
    }
    inline void insert(int x,int y)
    {
    	to[++e]=y;
    	nex[e]=beg[x];
    	beg[x]=e;
    }
    inline void dfs1(int x,int f,int d)
    {
    	int ch=0;
    	fa[x]=f;
    	size[x]=1;dep[x]=d;
    	for(register int i=beg[x];i;i=nex[i])
    		if(to[i]==f)continue;
    		else
    		{
    			dfs1(to[i],x,d+1);
    			size[x]+=size[to[i]];
    			if(size[to[i]]>ch)hson[x]=to[i],ch=size[to[i]];
    		}
    }
    inline void dfs2(int x,int tp)
    {
    	srt[x]=++cnt;
    	iit[cnt]=dep[x];
    	top[x]=tp;
    	if(hson[x])dfs2(hson[x],tp);
    	for(register int i=beg[x];i;i=nex[i])
    		if(to[i]==fa[x]||to[i]==hson[x])continue;
    		else dfs2(to[i],to[i]);
    	end[x]=cnt;
    }
    inline int LCA(int u,int v)
    {
    	while(top[u]!=top[v])
    	{
    		if(dep[top[u]]<dep[top[v]])std::swap(u,v);
    		u=fa[top[u]];
    	}
    	return dep[u]<dep[v]?u:v;
    }
    int main()
    {
    	read(n);read(m);
    	for(register int i=1;i<n;++i)
    	{
    		int u,v;
    		read(u);read(v);
    		insert(u,v);insert(v,u);
    	}
    	dfs1(1,0,1);dfs2(1,1);
    	T1.Build(1,1,n);
    	for(register int i=1;i<=n;++i)T2.fa[i]=fa[i];
    	while(m--)
    	{
    		int opt;
    		read(opt);
    		if(opt==1)
    		{
    			int x;
    			read(x);
    			T2.access(x);
    		}
    		if(opt==2)
    		{
    			int x,y,lca;
    			read(x);read(y);lca=LCA(x,y);
    			write(T1.QuerySm(1,1,n,srt[x])+T1.QuerySm(1,1,n,srt[y])-2*T1.QuerySm(1,1,n,srt[lca])+1,'
    ');
    		}
    		if(opt==3)
    		{
    			int x;
    			read(x);
    			write(T1.QueryMx(1,1,n,srt[x],end[x]),'
    ');
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    了解 C++ 默默编写并调用的函数
    确保对象在被使用前的初始化
    尽可能使用 const
    尽量多的以 const/enum/inline 替代 #define
    六 GPU 并行优化的几种典型策略
    五 浅谈CPU 并行编程和 GPU 并行编程的区别
    四 GPU 并行编程的存储系统架构
    三 GPU 并行编程的运算架构
    求解线性方程组的三种基本迭代法
    C#基础 特殊集合(栈集合、队列集合、哈希表集合)
  • 原文地址:https://www.cnblogs.com/hongyj/p/8717452.html
Copyright © 2011-2022 走看看