第一个操作比较麻烦,但可以看出它和lct里的access操作差不多,所以可以利用lct的性质巧妙维护操作1

直接用lct维护树中同颜色的链(因为染色操作是从$x$染到根所以同颜色的点一定形成一条链),权值就存$x$到根的路径权值$v_x$

对于操作1,在access每一次切换$x$的实儿子时,把原实儿子在splay中最左的点(也就是在原树中在$x$以下且同一条链上深度最浅的点)的子树权值$+1$,把新实儿子在splay中最左的点的子树权值$-1$(每一次切换,原实儿子的子树到根的路径上多了一种颜色,新实儿子的子树到根的路径上少了一种颜色)

对于操作2,容易看出答案是$v_x+v_y-2v_{lca_{x,y}}+1$

对于操作3,直接用线段树维护dfs序,就是查询区间最大值

这个lct的性质用得好哇

#include<stdio.h>
void swap(int&a,int&b){a^=b^=a^=b;}
int max(int a,int b){return a>b?a:b;}
int n,a[100010];
struct seg{
	int mx[400010],d[400010];
	void pushup(int x){mx[x]=max(mx[x<<1],mx[x<<1|1]);}
	void build(int l,int r,int x){
		if(l==r){
			mx[x]=a[l];
			return;
		}
		int mid=(l+r)>>1;
		build(l,mid,x<<1);
		build(mid+1,r,x<<1|1);
		pushup(x);
	}
	void add(int x,int v){
		d[x]+=v;
		mx[x]+=v;
	}
	void pushdown(int x){
		if(d[x]){
			add(x<<1,d[x]);
			add(x<<1|1,d[x]);
			d[x]=0;
		}
	}
	void modify(int L,int R,int v,int l,int r,int x){
		if(L<=l&&r<=R)return add(x,v);
		pushdown(x);
		int mid=(l+r)>>1;
		if(L<=mid)modify(L,R,v,l,mid,x<<1);
		if(mid<R)modify(L,R,v,mid+1,r,x<<1|1);
		pushup(x);
	}
	int query(int L,int R,int l,int r,int x){
		if(L<=l&&r<=R)return mx[x];
		pushdown(x);
		int mid=(l+r)>>1,ans=-1;
		if(L<=mid)ans=max(ans,query(L,R,l,mid,x<<1));
		if(mid<R)ans=max(ans,query(L,R,mid+1,r,x<<1|1));
		return ans;
	}
}s;
struct tree{
	int h[100010],nex[200010],to[200010],in[100010],ou[100010],fa[100010][17],dep[100010],M;
	void add(int a,int b){
		M++;
		to[M]=b;
		nex[M]=h[a];
		h[a]=M;
	}
	void dfs(int x){
		in[x]=++M;
		for(int i=h[x];i;i=nex[i]){
			if(to[i]!=fa[x][0]){
				fa[to[i]][0]=x;
				dep[to[i]]=dep[x]+1;
				dfs(to[i]);
			}
		}
		ou[x]=M;
	}
	void pre(){
		int i,j,x,y;
		for(i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y);
			add(y,x);
		}
		dep[1]=1;
		M=0;
		dfs(1);
		for(j=1;j<17;j++){
			for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
		}
		for(i=1;i<=n;i++)a[in[i]]=dep[i];
		s.build(1,n,1);
	}
	void modify(int x,int v){
		s.modify(in[x],ou[x],v,1,n,1);
	}
	int get(int x){
		return s.query(in[x],in[x],1,n,1);
	}
	int sub(int x){
		return s.query(in[x],ou[x],1,n,1);
	}
	int lca(int x,int y){
		int i;
		if(dep[x]<dep[y])swap(x,y);
		for(i=16;i>=0;i--){
			if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
		}
		if(x==y)return x;
		for(i=16;i>=0;i--){
			if(fa[x][i]!=fa[y][i]){
				x=fa[x][i];
				y=fa[y][i];
			}
		}
		return fa[x][0];
	}
}t;
struct lct{
	int fa[100010],ch[100010][2],l[100010];
	void pre(){
		int i;
		for(i=2;i<=n;i++)fa[i]=t.fa[i][0];
		for(i=1;i<=n;i++)l[i]=i;
	}
	#define ls ch[x][0]
	#define rs ch[x][1]
	void pushup(int x){
		if(ls)
			l[x]=l[ls];
		else
			l[x]=x;
	}
	void rot(int x){
		int y,z,f,b;
		y=fa[x];
		z=fa[y];
		f=ch[y][0]==x;
		b=ch[x][f];
		fa[x]=z;
		fa[y]=x;
		if(b)fa[b]=y;
		ch[x][f]=y;
		ch[y][f^1]=b;
		if(ch[z][0]==y)ch[z][0]=x;
		if(ch[z][1]==y)ch[z][1]=x;
		pushup(y);
		pushup(x);
	}
	bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
	void splay(int x){
		int y,z;
		while(!isrt(x)){
			y=fa[x];
			z=fa[y];
			if(!isrt(y))rot((ch[z][0]==y&&ch[y][0]==x)||(ch[z][1]==y&&ch[y][1]==x)?y:x);
			rot(x);
		}
	}
	void access(int x){
		int y=0;
		while(x){
			splay(x);
			if(rs)t.modify(l[rs],1);
			rs=y;
			if(y)t.modify(l[y],-1);
			pushup(x);
			y=x;
			x=fa[x];
		}
	}
}l;
int main(){
	int m,i,x,y;
	scanf("%d%d",&n,&m);
	t.pre();
	l.pre();
	while(m--){
		scanf("%d%d",&i,&x);
		if(i==1)l.access(x);
		if(i==2){
			scanf("%d",&y);
			printf("%d\n",t.get(x)+t.get(y)-(t.get(t.lca(x,y))<<1)+1);
		}
		if(i==3)printf("%d\n",t.sub(x));
	}
}

[BZOJ4817]树点涂色的更多相关文章

  1. [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]

    题面 传送门 思路 $LCT$ 我们发现,这个1操作,好像非常像$LCT$里面的$Access$啊~ 那么我们尝试把$Access$操作魔改成本题中的涂色 我们令$LCT$中的每一个$splay$链代 ...

  2. 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)

    [BZOJ4817]树点涂色(LCT,线段树,树链剖分) 题面 BZOJ Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义 ...

  3. 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树

    [BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...

  4. [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)

    4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 692  Solved: 408[Submit][Status ...

  5. 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]

    树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1 ...

  6. [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)

    4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 629  Solved: 371[Submit][Status ...

  7. [Sdoi2017]树点涂色 [lct 线段树]

    [Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...

  8. 「SDOI2017」树点涂色 解题报告

    「SDOI2017」树点涂色 我sb的不行了 其实一开始有一个类似动态dp的想法 每个点维护到lct树上到最浅点的颜色段数,然后维护一个\(mx_{0,1}\)也就是是否用虚儿子的最大颜色 用个set ...

  9. P3703 [SDOI2017]树点涂色

    P3703 [SDOI2017]树点涂色 链接 分析: 首先对于询问,感觉是线段树维护dfs序,每个点记录到根的颜色个数.第二问差分,第三问区间取max. 那么考虑修改,每次将一个点的颜色变成和父节点 ...

随机推荐

  1. 继承spring的validator接口,实现对数据的校验

    在org.springframework.validation这个包中提供了一些对数据校验的方法,其中Validator接口是其中的一个. 现在用Validator接口,完成对数据的校验. 第一步:先 ...

  2. idea初学建立maven项目报错

    原理,是因为你没把新创建好的maven项目给设置成一个可被tomcat部署的web项目 参考此博文,讲的非常详细: 归根到底是因为web项目的部署问题: 解决方案:在创建的到时候,idea下部会提示是 ...

  3. Substrings(hdu 4455)

    题意: 给定一个序列ai,个数为n.再给出一系列w:对于每个w,求序列中,所有长度为w的连续子串中的权值和,子串权值为子串中不同数的个数. /* dp[i]表示长度为i的序列不同元素个数之和. 考虑从 ...

  4. [ZOJ2341]Reactor Cooling解题报告|带上下界的网络流|无源汇的可行流

    Reactor Cooling The terrorist group leaded by a well known international terrorist Ben Bladen is bul ...

  5. Ubuntu 下nginx 的卸载 与重新装

    由于本人把自己服务器的nginx 给玩坏了,不得已选择卸载重新安装,(先让我哭一会) 然后我把/usr/sbin/nginx  和/etc/nginx 和/usr/share/nginx 和 /usr ...

  6. 应对ubuntu linux图形界面卡住的方法

    有的时候,我的ubuntu图形界面会卡住,当然这个时候你可以重新启动,不过最好的办法应该是结束这个桌面进程 那桌面卡住了怎么来结束桌面进程呢? 这时候就需要打开tty了 按下键盘ctrl+alt+f1 ...

  7. 内存管理相关函数 -- Linux【转】

    转自:http://blog.csdn.net/cy_cai/article/details/47001245 1.kmalloc()/kfree() static __always_inline v ...

  8. UVALIVE 3939 Plucking fruits

    并查集解决.代码跑的有够慢.应该可以通过边权排序优化. #include <map> #include <set> #include <list> #include ...

  9. Anaconda 2和3在Win10上共存

    1. 安装Anaconda 2和3 Anaconda 2中的python2为主,Anaconda 3中的python3为辅.先装Anaconda 2,并在安装时选择注册为系统python,再装Anac ...

  10. js监听不到组合键

    我在js文件中写代码,监听 ctrl + enter 组合键,但是一直监听不到.只能监听到单个键. 后来我将监听的代码放到html页面中去,就能监听到了. 这个问题困扰我很久,记录下!