• Luogu3703 SDOI2017树点涂色


    Description

    Luogu3703

    有一棵树,点带颜色,初始颜色各不相同

    定义路径价值为路径上面不同颜色的个数

    请写出一种数据结构,支持以下几种操作:

    (1.) 更新根到某点的链上的颜色为一种新的

    (2.) 求一个点子树到中到根路径价值最大的点(求最大价值)

    (3.) 求两点之间的路径价值

    Solution

    首先考虑的是每个颜色的贡献

    看到(1) 操作,想到了 (Link-Cut Tree)

    但是看到 (2,3) 操作,想到了树剖

    然后发现树剖中可以拿来解决这题的其实是线段树维护 (dfn)

    (2) 操作变成了区间最值,(3) 操作变成了树上差分,再做一下 (lca)

    然后还是 (lct)

    (1) 操作的本质变成了 (access)

    就是像 (HH) 的项链那样子,把原来的那个颜色删除,在新的地方添加一个新的颜色

    然后就变成了实现代码题(真的很难实现)

    细节总览:

    (1.) 这里的 (lct) 没有维护信息,只是拿来整路径的

    (2.) 线段树的实现比较恶心,修改的时候不能 (l<=l(p)&&r(p)<=r,)得两边都满足的时候才能改

    (3.) (access) 的时候先对子树上面的 (val) 减去 (1),之后跳到另一棵 (splay) 的时候给那棵的点权再加上 (1)

    (其实就是依据实际情况对两种数据结构进行了调整)

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm{
    	inline int read()
    	{
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar();
    		return res*f;
    	}
    	const int N=1e5+10;
    	int fa[N],ls[N],rs[N],l[N],r[N],dfn[N],tot,anc[N][20];
    	int head[N],cnt,dep[N],n,m;
    	struct node{
    		int to,nxt;
    	}e[N<<1];
    	inline void add(int u,int v)
    	{
    		e[++cnt].nxt=head[u]; e[cnt].to=v;
    		return head[u]=cnt,void();
    	}
    	inline void dfs(int x,int fat)
    	{
    		dep[x]=dep[fat]+1; dfn[++tot]=x; l[x]=tot; anc[x][0]=fat; fa[x]=fat;
    		for(int i=1;(1<<i)<=dep[x];++i) anc[x][i]=anc[anc[x][i-1]][i-1];
    		for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fat) dfs(e[i].to,x);
    		r[x]=tot;
    		return ;
    	}
    	inline int lca(int x,int y)
    	{
    		if(dep[x]<dep[y]) swap(x,y);
    		for(int i=19;i>=0;--i) if(dep[anc[x][i]]>=dep[y]) x=anc[x][i];
    		if(x==y) return x;
    		for(int i=19;i>=0;--i) if(anc[x][i]!=anc[y][i]) x=anc[x][i],y=anc[y][i];
    		return anc[x][0];
    	}
    	struct tree{
    		int maxx,fl,l,r;
    		#define maxx(p) t[p].maxx
    		#define l(p) t[p].l
    		#define r(p) t[p].r
    		#define fl(p) t[p].fl
    	}t[N<<2];
    	inline void push_up(int x){return maxx(x)=max(maxx(x<<1),maxx(x<<1|1)),void();}
    	inline void build(int p,int st,int ed)
    	{
    		l(p)=st; r(p)=ed;
    		if(st==ed) return maxx(p)=dep[dfn[st]],void();
    		int mid=(st+ed)>>1; build(p<<1,st,mid); build(p<<1|1,mid+1,ed); 
    		return push_up(p);
    	}
    	inline void push_down(int p)
    	{
    		if(fl(p)) 
    		{
    			fl(p<<1)+=fl(p); maxx(p<<1)+=fl(p);
    			maxx(p<<1|1)+=fl(p); fl(p<<1|1)+=fl(p);
    		} return fl(p)=0,void();
    	}
    	inline void update(int p,int st,int ed,int val)
    	{
    		if(st==l(p)&&r(p)==ed) return fl(p)+=val,maxx(p)+=val,void();
    		int mid=(l(p)+r(p))>>1; push_down(p);
    		if(ed<=mid) update(p<<1,st,ed,val);
    		else if(st>mid) update(p<<1|1,st,ed,val);
    		else update(p<<1,st,mid,val),update(p<<1|1,mid+1,ed,val);
    		return push_up(p);
    	}
    	inline int query(int p,int st,int ed)
    	{
    		if(st==l(p)&&r(p)==ed) return maxx(p);
    		int mid=(l(p)+r(p))>>1; push_down(p);
    		if(ed<=mid) return query(p<<1,st,ed);
    		if(st>mid) return query(p<<1|1,st,ed);
    		return max(query(p<<1|1,mid+1,ed),query(p<<1,st,mid));
    	}
    	inline bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
    	inline void rotate(int x)
    	{
    		int y=fa[x],z=fa[y];
    		if(!isroot(y)) if(ls[z]==y) ls[z]=x; else rs[z]=x;
    		if(ls[y]==x) ls[y]=rs[x],fa[rs[x]]=y,rs[x]=y;
    		else rs[y]=ls[x],fa[ls[x]]=y,ls[x]=y;
    		fa[x]=z; fa[y]=x;
    		return ;
    	}
    	inline void splay(int x)
    	{
    		while(!isroot(x)) 
    		{
    			int y=fa[x],z=fa[y];
    			if(!isroot(y)) rotate((ls[y]==x)^(ls[z]==y)?x:y);
    			rotate(x);
    		} return ;
    	}
    	inline int findroot(int x){while(ls[x]) x=ls[x]; return x;}
    	inline void access(int x)
    	{
                    //rs[x] 在这里是深度大的点,而ls[x] 是深度小的
    		for(int y=0;x;x=fa[y=x]) 
    		{
    			splay(x);
    			if(rs[x]) 
    			{
    				int t=rs[x]; t=findroot(t);
    				update(1,l[t],r[t],1);//把新的颜色添加上去
    			} rs[x]=y; //lct操作
    			if(rs[x])
    			{
    				int t=rs[x]; t=findroot(t);
    				update(1,l[t],r[t],-1);//删掉原来颜色的贡献
    			}
    		} return ;
    	}
    	signed main()
    	{
    		n=read(); m=read();
    		for(int i=1,u,v;i<n;++i) u=read(),v=read(),add(u,v),add(v,u);
    		dfs(1,0); build(1,1,n);
    		while(m--)
    		{
    			int opt=read();
    			if(opt==1) access(read());
    			if(opt==2)
    			{
    				int x=read(),y=read(),lc=lca(x,y);
    				x=l[x],y=l[y],lc=l[lc];
    				printf("%lld
    ",query(1,x,x)+query(1,y,y)-2*query(1,lc,lc)+1);
    			}
    			if(opt==3)
    			{
    				int x=read();
    				printf("%lld
    ",query(1,l[x],r[x]));
    			}
    		}
    		return 0;
    	}
    }
    signed main(){return yspm::main();}
    
    
  • 相关阅读:
    Safari-IoS调试
    前端加密技术
    gulp入门
    xss攻击
    xml 解析
    python 基本语法
    python初识
    字节
    神奇的算式
    linux-虚拟机安装
  • 原文地址:https://www.cnblogs.com/yspm/p/13193820.html
Copyright © 2020-2023  润新知