给定一棵有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
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;
}