bzoj 4817: [Sdoi2017]树点涂色 lct+线段树

Description

Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作

Input

第一行两个数n,m。
接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
接下来m行,表示操作,格式见题目描述
1<=n,m<=100000

Output

每当出现2,3操作,输出一行。
如果是2操作,输出一个数表示路径的权值

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

题解:

lct维护第一个操作,每断开一次相当于子树+1,接上子树-1

然后线段树维护dfs统计答案

key:利用lct,access的特殊性质来维护


注意:子树修改时要找链上深度最浅的点,而不是当前splay的根

链剖lca忘更新sz,血T


第一次用namespace打代码好写好调,以后多写类似的版


#include<bits/stdc++.h>
using namespace std;
#define maxn 100020

struct node{
	int next,to;
}e[maxn * 2];
int head[maxn],cnt,n,m,top[maxn],sz[maxn],dth[maxn],son[maxn],fa[maxn],dfstime,a[maxn],l[maxn],r[maxn];

struct seg{
	#define lson x << 1,l,mid
	#define rson x << 1|1,mid+1,r
	#define N 400020
	int mx[N],add[N];

	inline void update(int x){
		mx[x] = max(mx[x << 1],mx[x << 1|1]);
	}
	void build(int x,int l,int r){
		if ( l == r ){ mx[x] = dth[a[l]]; return; }
		register int mid = (l + r) >> 1;
		build(lson) , build(rson);
		update(x);
	}
	inline void Add(int x,int d){
		add[x] += d , mx[x] += d;
	}
	inline void pushdown(int x){
		if ( add[x] != 0 ){
			Add(x << 1,add[x]);
			Add(x << 1|1,add[x]);
			add[x] = 0;
		}
	}	
	void modify(int x,int l,int r,int ls,int rs,int d){
		if ( ls <= l && rs >= r ){ Add(x,d); return; }
		register int mid = (l + r) >> 1;
		pushdown(x);
		if ( ls <= mid ) modify(lson,ls,rs,d);
		if ( rs > mid ) modify(rson,ls,rs,d);
		update(x);
	}
	int query(int x,int l,int r,int id){
		if ( l == r ) return mx[x];
		register int mid = (l + r) >> 1;
		pushdown(x);
		if ( id <= mid ) return query(lson,id);
		return query(rson,id);
	}
	int query(int x,int l,int r,int ls,int rs){
		if ( ls <= l && rs >= r ) return mx[x];
		register int mid = (l + r) >> 1;int cur = 0;
		pushdown(x);
		if ( ls <= mid ) cur = query(lson,ls,rs);
		if ( rs > mid ) cur = max(cur,query(rson,ls,rs));
		return cur;
	}
}T;
namespace LCT{
	#define ls(x) ch[x][0]
	#define rs(x) ch[x][1]	
	#define N 100020
	int fa[N],ch[N][2],sz[N],rev[N]; //树的形态固定,fa[x]初始时应该用树上的fa
	int stack_[maxn],tops = -1;
	inline void update(int x){
		sz[x] = sz[ls(x)] + sz[rs(x)] + 1;
	}
	inline bool isroot(int x){
		return (ls(fa[x]) != x) && (rs(fa[x]) != x);
	}
	inline void reverse(int x){
		if ( !x ) return;
		rev[x] ^= 1 , swap(ls(x),rs(x));
	}
	inline void pushdown(int x){
		if ( rev[x] ){
			reverse(ls(x));
			reverse(rs(x));
			rev[x] = 0;
		}
	}
	inline void rotate(int x){
		int y = fa[x] , t = rs(y) == x , z = ch[x][1 - t];
		fa[x] = fa[y];
		if ( !isroot(y) ) ch[fa[y]][rs(fa[y]) == y] = x;
		fa[y] = x , ch[x][1 - t] = y;
		if ( z ) fa[z] = y;
		ch[y][t] = z;
		//update(y);
	}
	inline void splay(int x){
		tops = -1;
		for (int i = x ; !isroot(i) ; i = fa[i]) stack_[++tops] = fa[i];
		while ( ~tops ) pushdown(stack_[tops--]);		
		pushdown(x);
		while ( !isroot(x) ){
			int y = fa[x] , z = fa[y];
			if ( !isroot(y) && !((ls(z) == y) ^ (ls(y) == x)) ) rotate(y);
			else rotate(x);
			if ( !isroot(x) ) rotate(x);	
		}
		//update(x);
	}
	void access(int x){
		int t = 0,y = 0;
		for (;x;x = fa[x]){
			splay(x);
			if ( t ){
			   	y = t;
				while ( ls(y) ) y = ls(y);
				T.modify(1,1,n,l[y],r[y],-1); //要对当前链上深度最小的区间修改,不能直接用splay的根
			}
			if ( rs(x) ){
				y = rs(x);
				while ( ls(y) ) y = ls(y); //同理,找深度最小
				T.modify(1,1,n,l[y],r[y],1);
			}
		 	ch[x][1] = t , t = x; //update(x)
		}
	}
}

inline void adde(int x,int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}
void dfs(int x){
	sz[x] = 1 , l[x] = ++dfstime , a[dfstime] = x;
	for (int i = head[x] ; i ; i = e[i].next){
		if ( e[i].to == fa[x] ) continue;
		dth[e[i].to] = dth[x] + 1;
		fa[e[i].to] = x ;
		dfs(e[i].to);
		sz[x] += sz[e[i].to];
		if ( sz[son[x]] < sz[e[i].to] ) son[x] = e[i].to;
	}
	r[x] = dfstime;
}
void dfs2(int x){
	if ( son[x] ){
		top[son[x]] = top[x];
		dfs2(son[x]);
	}
	for (int i = head[x] ; i ; i = e[i].next){
		if ( e[i].to == fa[x] || e[i].to == son[x] ) continue;
		top[e[i].to] = e[i].to;
		dfs2(e[i].to);
	}
}
inline int lca(int x,int y){
	while ( top[x] != top[y] ){
		if ( dth[top[x]] < dth[top[y]] ) swap(x,y);
		x = fa[top[x]];
	}
	if ( dth[x] < dth[y] ) return x;
	return y;
}
int main(){
	freopen("input.txt","r",stdin);
	scanf("%d %d",&n,&m);
	for (int i = 1 ; i < n ; i++){
		int x,y;
		scanf("%d %d",&x,&y);
		adde(x,y) , adde(y,x);
	}
	dth[1] = 1 , dfs(1) , top[1] = 1, dfs2(1);
	memcpy(LCT::fa,fa,sizeof(fa));
	T.build(1,1,n);
	while ( m-- ){
		int t,x,y,lca_;
		scanf("%d",&t);
		if ( t == 1 ){
			scanf("%d",&x);
			LCT::access(x);
		}
		else if ( t == 2 ){
			scanf("%d %d",&x,&y);
			lca_ = lca(x,y);
			printf("%d\n",T.query(1,1,n,l[x]) + T.query(1,1,n,l[y]) - 2 * T.query(1,1,n,l[lca_]) + 1);
		}
		else{
			scanf("%d",&x);
			printf("%d\n",T.query(1,1,n,l[x],r[x]));
		}
	//	cout<<T.query(1,1,n,l[3])<<endl;
	}
	return 0;
}



猜你喜欢

转载自blog.csdn.net/weixin_42484877/article/details/80925160