HYSBZ—2243 染色(LCT动态树)

给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“ 112221 ” 由3段组成:“ 11 ” 、“ 222 ” 和“ 1 ” 。
请你写一个程序依次完成这m个操作。

Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

Output
对于每个询问操作,输出一行答案。
Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
3
1
2

Hint

数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。


LCT做法

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define F(x) tree[x].fa
#define REV(x) tree[x].rev
#define LC(x) tree[x].child[0]
#define RC(x) tree[x].child[1]
#define C(x) tree[x].color
#define L_c(x) tree[x].left_color
#define R_c(x) tree[x].right_color
#define Size 300010
using namespace std;
inline int read(){
	int sum=0,fg=1;char c=getchar();
	while(c<'0' || c>'9'){if(c=='-')fg=-1;c=getchar();}
	while(c>='0' && c<='9'){sum=sum*10+c-'0';c=getchar();}
	return sum*fg;
}
struct lct{
	int fa,child[2],rev,mark;
	int color,left_color,right_color,sum;
}tree[Size];
int be[Size],ne[Size],to[Size],e;
struct link_cut_tree{
	inline bool isroot(int x){
		return LC(F(x))!=x && RC(F(x))!=x;
	}
	inline void pushup(int x){
		tree[x].sum=tree[LC(x)].sum+tree[RC(x)].sum+1;
		if(LC(x)){
			L_c(x)=L_c(LC(x));
			tree[x].sum-=(R_c(LC(x))==C(x));
		}
		else L_c(x)=C(x);
		if(RC(x)){
			R_c(x)=R_c(RC(x));
			tree[x].sum-=(L_c(RC(x))==C(x));
		}
		else R_c(x)=C(x);
	}
	inline void make_color(int x,int color){
		C(x)=L_c(x)=R_c(x)=tree[x].mark=color;tree[x].sum=1;
	}
	inline void pushdown(int x){
		if(REV(x)){
			REV(x)^=1;REV(LC(x))^=1;REV(RC(x))^=1;
			swap(LC(LC(x)),RC(LC(x)));swap(L_c(LC(x)),R_c(LC(x)));
			swap(LC(RC(x)),RC(RC(x)));swap(L_c(RC(x)),R_c(RC(x)));
		}
		if(tree[x].mark){
			if(LC(x))make_color(LC(x),tree[x].mark);
			if(RC(x))make_color(RC(x),tree[x].mark);
			tree[x].mark=0;
		}
	}
	void Pushdown(int x){
		if(!isroot(x))Pushdown(F(x));
		pushdown(x);
	}
	inline void rotate(int x){
		int A=F(x),B=F(A);bool w=(RC(A)==x);
		if(!isroot(A)){
			if(LC(B)==A)LC(B)=x;
			else if(RC(B)==A)RC(B)=x;
		}
		F(tree[x].child[w^1])=A;F(A)=x;F(x)=B;
		tree[A].child[w]=tree[x].child[w^1];tree[x].child[w^1]=A;
		pushup(A);pushup(x);
	}
	inline void splay(int x){
		Pushdown(x);
		while(!isroot(x)){
			if(!isroot(F(x)))rotate(x);
			rotate(x);
		}
	}
	inline void access(int x){
		for(int i=0;x;i=x,x=F(x))splay(x),RC(x)=i,pushup(x);
	}
	inline int find_root(int x){
		access(x);splay(x);
		while(LC(x))x=LC(x);
		return x;
	}
	inline void reverse(int x){
		access(x);splay(x);REV(x)^=1;
		swap(LC(x),RC(x));swap(L_c(x),R_c(x));
	}
	inline void update(int x,int y,int w){
		reverse(x);access(y);splay(y);
		make_color(y,w);
	}
	inline int query(int x,int y){
		reverse(x);access(y);splay(y);
		return tree[y].sum;
	}
}LCT;
void add(int x,int y){to[++e]=y;ne[e]=be[x];be[x]=e;}
void dfs(int x,int fa){
	for(int i=be[x];i;i=ne[i]){
		int v=to[i];
		if(v!=fa){
			tree[v].fa=x;
			dfs(v,x);
		}
	}
}
int main(){
	int n=read(),m=read();
	for(int i=1;i<=n;i++){LCT.make_color(i,read()+1);tree[i].mark=0;}
	for(int i=1;i<n;i++){int x=read(),y=read();add(x,y);add(y,x);}
	dfs(1,0);
	char tp[10];
	while(m--){
		scanf("%s",tp);
		if(tp[0]=='Q'){int x=read(),y=read();printf("%d\n",LCT.query(x,y));}
		else{int x=read(),y=read(),w=read();LCT.update(x,y,w+1);}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值