아이디어 : 검토 간격 세그먼트 선분의 색을 유지하는 구간의 수, 색상 범위의 좌측 단부 지점 색상 범위의 우단.
쿼리 경로가 여러 섹션으로 나누어 져 있기 때문에 때, 쿼리, 우리는 엔드 포인트 색상에 대해 유지해야합니다.
예를 들어 쿼리 UV : U와 V 가능성, 컬러 POS1 각 점프 엔드 포인트, POS2 후 기록해야 이동한다. 예를 들어, 쿼리 :
쿼리 UX. 체인 분할 트리 x> 새로운 번호 U 다음의 새로운 번호.
세그먼트 트리 x 축에서 모든 문의> 유. 색 조회 번호, LC 및 Rc를 유지하는 경우에는 동일 색상 값이 부 종료점 색에 대해이고, Rc를 동일 색상 POS1 여부를 판정 -1.
순위 = LC 및 색상.
우리가 다음에 v의 POS1 교환 및 POS2. POS1과 점프 경우 각각 비교된다.
마지막 점프합니다. : 우리는주의를 기울여야한다
LC와 POS1,이, Rc POS2을 비교하기.
내부 세그먼트 트리 동정 범위 쿼리는 엔드 포인트 색상을 비교하기 위해주의를 기울여야한다.
//#include <bits/stdc++.h>
//#define Rint register int
//using namespace std;
//
//int main(){
//
// srand(time(0));
// int n=rand()%5+5, m=rand()%7+1;
// printf("%d %d\n", n, m);
// for(int i=1; i<=n; i++){
// cout<<rand()%4+1<<" ";
// }
// cout<<endl;
// for(int i=2; i<=n; i++){
// cout<<i<<" "<<rand()%(i-1)+1<<endl;
// }
// for(int i=1; i<=m; i++){
// int k, a, b, c;
// k=rand()%2;
// if(k){
// a=rand()%(n)+1;
// b=rand()%(n)+1;
// c=rand()%3+1;
// cout<<"C "<<a<<" "<<b<<" "<<c<<endl;
// }
// else{
// a=rand()%(n)+1;
// b=rand()%(n)+1;
// cout<<"Q "<<a<<" "<<b<<endl;
// }
// }
//
// return 0;
//}
#include <bits/stdc++.h>
#define Rint register int
using namespace std;
#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define len (r-l+1)
const int maxn=1000005;
int n,m;
//见题意
int tot,head[maxn],nex[maxn],to[maxn], w[maxn], wt[maxn];
//链式前向星数组,w[]、wt[]初始点权数组
int lc[maxn<<2], rc[maxn<<2], sc[maxn<<2], laz[maxn<<2];
//线段树数组 左端颜色 右端颜色 区间标记
int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn];
//son[]重儿子编号,id[]新编号,fa[]父亲节点,cnt dfs_clock/dfs序,dep[]深度,siz[]子树大小,top[]当前链顶端节点
int pos1, pos2, Lc, Rc,res;
//链左端颜色 链右端颜色 查询答案
inline void add(int x,int y){//链式前向星加边
to[++tot]=y;
nex[tot]=head[x];
head[x]=tot;
}
//-------------------------------------- 以下为线段树
inline void build(int rt,int l,int r){
if(l==r){
lc[rt]=rc[rt]=wt[l];
sc[rt]=1;
laz[rt]=0;
return;
}
build(lson);
build(rson);
sc[rt]=sc[rt<<1]+sc[rt<<1|1];
if(rc[rt<<1]==lc[rt<<1|1]){
sc[rt]--;
}
lc[rt]=lc[rt<<1];
rc[rt]=rc[rt<<1|1];
}
void down(int rt){
if(laz[rt]){
laz[rt<<1]=laz[rt<<1|1]=laz[rt];
sc[rt<<1]=sc[rt<<1|1]=sc[rt];
lc[rt<<1]=lc[rt<<1|1]=rc[rt<<1]=rc[rt<<1|1]=laz[rt];
laz[rt]=0;
}
}
inline void update(int rt, int l, int r, int L, int R, int k){
if(L<=l&&r<=R){
laz[rt]=lc[rt]=rc[rt]=k;
sc[rt]=1;
//cout<<"L "<<l<<" "<<r<<" "<<lc[rt]<<" "<<rc[rt]<<" "<<sc[rt]<<endl;
return;
}
else{
down(rt);
if(L<=mid)update(lson,L,R,k);
if(R>mid)update(rson,L,R,k);
sc[rt]=sc[rt<<1]+sc[rt<<1|1];
if(rc[rt<<1]==lc[rt<<1|1]){
sc[rt]--;
}
lc[rt]=lc[rt<<1];
rc[rt]=rc[rt<<1|1];
//cout<<"L "<<l<<" "<<r<<" "<<lc[rt]<<" "<<rc[rt]<<" "<<sc[rt]<<endl;
}
}
inline void query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R){
res+=sc[rt];
if(lc[rt]==Rc){
res--;
}
if(L==l){
Lc=lc[rt];
}
Rc=rc[rt];
return;
}
else{
if(laz[rt])down(rt);
if(L<=mid)query(lson,L,R);
if(R>mid)query(rson,L,R);
}
}
/*
7 100
1 1 1 1 1 1 1
1 2
2 3
3 5
3 4
2 6
1 7
C 1 2 2
Q 7 3
*/
//-------------------------------------- 以上为线段树
inline int Q(int x, int y){
pos1=pos2=0;res=0;
while(top[x]!=top[y]){//当两个点不在同一条链上
if(dep[top[x]]<dep[top[y]])swap(x,y), swap(pos1,pos2);//把x点改为所在链顶端的深度更深的那个点
Lc=Rc=0;
query(1,1,n,id[top[x]],id[x]);//ans加上x点到x所在链顶端 这一段区间的点权和
x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
if(Rc==pos1){
res--;
}
pos1=Lc;
}
//直到两个点处于一条链上
Lc=Rc=0;
if(dep[x]>dep[y])swap(x,y), swap(pos1,pos2);//把x点深度更深的那个点
query(1,1,n,id[x],id[y]);//这时再加上此时两个点的区间和即可
if(Lc==pos1){
res--;
}
if(Rc==pos2){
res--;
}
return res;
}
inline void U(int x, int y, int k){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,1,n,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
update(1,1,n,id[x],id[y],k);
}
//-------------------------------------- 以下为模板
inline void dfs1(int x,int f,int deep){
dep[x]=deep;
fa[x]=f;
siz[x]=1;
int maxson=-1;
for(Rint i=head[x];i;i=nex[i]){
int y=to[i];
if(y==f)continue;
dfs1(y,x,deep+1);
siz[x]+=siz[y];
if(siz[y]>maxson)son[x]=y,maxson=siz[y];
}
}
inline void dfs2(int x,int topf){
id[x]=++cnt;
top[x]=topf;
//cout<<x<<" ; "<<cnt<<endl;
wt[cnt]=w[x];//把每个点的初始值赋到新编号上来
if(!son[x])return;
dfs2(son[x],topf);
for(Rint i=head[x];i;i=nex[i]){
int y=to[i];
if(y==fa[x]||y==son[x])continue;
dfs2(y,y);
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++){
scanf("%d", &w[i]);
}
for(Rint i=1;i<n;i++){
int a,b;
scanf("%d%d", &a, &b);
add(a,b);add(b,a);
}
dfs1(1,0,1);
dfs2(1,1);
build(1,1,n);
while(m--){
char s[5];
int a, b, c;
scanf("%s", s);
if(s[0]=='C'){
scanf("%d%d%d", &a, &b, &c);
U(a, b, c);
}
else{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", Q(a, b));
}
}
}
/*
6 6
4 2 2 4 3 1
2 1
3 1
4 2
5 3
6 3
C 6 2 1
C 1 2 3
Q 4 3
*/