#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
typedef long long LL;
inline int read_int(){
int t=0;bool sign=false;char c=getchar();
while(!isdigit(c)){sign|=c=='-';c=getchar();}
while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();}
return sign?-t:t;
}
inline LL read_LL(){
LL t=0;bool sign=false;char c=getchar();
while(!isdigit(c)){sign|=c=='-';c=getchar();}
while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();}
return sign?-t:t;
}
inline char get_char(){
char c=getchar();
while(c==' '||c=='\n'||c=='\r')c=getchar();
return c;
}
inline void write(LL x){
register char c[21],len=0;
if(!x)return putchar('0'),void();
if(x<0)x=-x,putchar('-');
while(x)c[++len]=x%10,x/=10;
while(len)putchar(c[len--]+48);
}
inline void space(LL x){write(x),putchar(' ');}
inline void enter(LL x){write(x),putchar('\n');}
const int MAXN=1e5+5;
int lef_color,rig_color;
struct Tree{
int a[MAXN<<2],lazy[MAXN<<2],lc[MAXN<<2],rc[MAXN<<2],sum[MAXN<<2];
int lef[MAXN<<2],rig[MAXN<<2];
void init(int n,int *w){
_rep(i,1,n)
a[i]=w[i];
build(1,1,n);
}
void push_up(int k){
sum[k]=sum[k<<1]+sum[k<<1|1];
lc[k]=lc[k<<1];
rc[k]=rc[k<<1|1];
if(rc[k<<1]==lc[k<<1|1])
sum[k]--;
}
void build(int k,int L,int R){
lef[k]=L,rig[k]=R;
int M=L+R>>1;
if(L==R){
sum[k]=1;
lc[k]=rc[k]=a[M];
return;
}
build(k<<1,L,M);
build(k<<1|1,M+1,R);
push_up(k);
}
void push_lazy(int k,int lz){
lazy[k]=lc[k]=rc[k]=lz;
sum[k]=1;
}
void push_down(int k){
if(lazy[k]){
push_lazy(k<<1,lazy[k]);
push_lazy(k<<1|1,lazy[k]);
lazy[k]=0;
}
}
int query(int k,int L,int R){
if(L<=lef[k]&&rig[k]<=R){
if(lef[k]==L)
lef_color=lc[k];
if(rig[k]==R)
rig_color=rc[k];
return sum[k];
}
push_down(k);
int mid=lef[k]+rig[k]>>1;
if(mid>=R)
return query(k<<1,L,R);
else if(mid<L)
return query(k<<1|1,L,R);
else{
if(rc[k<<1]==lc[k<<1|1])
return query(k<<1,L,R)+query(k<<1|1,L,R)-1;
else
return query(k<<1,L,R)+query(k<<1|1,L,R);
}
}
void update(int k,int L,int R,int c){
if(L<=lef[k]&&rig[k]<=R){
push_lazy(k,c);
return;
}
push_down(k);
int mid=lef[k]+rig[k]>>1;
if(mid>=L)
update(k<<1,L,R,c);
if(mid<R)
update(k<<1|1,L,R,c);
push_up(k);
}
}tree;
struct Edge{
int to,next;
}edge[MAXN<<1];
int head[MAXN],m;
void Insert(int u,int v){
edge[++m].to=v;
edge[m].next=head[u];
head[u]=m;
}
int d[MAXN],w[MAXN],sz[MAXN],f[MAXN],dfs_id[MAXN],dfs_t;
int h_son[MAXN],mson[MAXN],p[MAXN],dfs_w[MAXN];
void dfs_1(int u,int fa,int depth){
sz[u]=1;f[u]=fa;d[u]=depth;mson[u]=0;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v==fa)
continue;
dfs_1(v,u,depth+1);
sz[u]+=sz[v];
if(sz[v]>mson[u]){
h_son[u]=v;
mson[u]=sz[v];
}
}
}
void dfs_2(int u,int top){
dfs_id[u]=++dfs_t;p[u]=top;dfs_w[dfs_t]=w[u];
if(mson[u])
dfs_2(h_son[u],top);
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v==f[u]||v==h_son[u])
continue;
dfs_2(v,v);
}
}
int query_path(int u,int v){
int c1=-1,c2=-1,ans=0;
while(p[u]!=p[v]){
if(d[p[u]]<d[p[v]]){
swap(u,v);
swap(c1,c2);
}
ans+=tree.query(1,dfs_id[p[u]],dfs_id[u]);
if(c1==rig_color)
ans--;
c1=lef_color;
u=f[p[u]];
}
if(d[u]>d[v]){
swap(u,v);
swap(c1,c2);
}
ans+=tree.query(1,dfs_id[u],dfs_id[v]);
if(c1==lef_color)
ans--;
if(rig_color==c2)
ans--;
return ans;
}
void update_path(int u,int v,int w){
while(p[u]!=p[v]){
if(d[p[u]]<d[p[v]])
swap(u,v);
tree.update(1,dfs_id[p[u]],dfs_id[u],w);
u=f[p[u]];
}
if(d[u]>d[v])
swap(u,v);
tree.update(1,dfs_id[u],dfs_id[v],w);
}
int main()
{
int n=read_int(),q=read_int(),root=1,x,y;
char opt;
_rep(i,1,n)
w[i]=read_int();
_for(i,1,n){
x=read_int(),y=read_int();
Insert(x,y);
Insert(y,x);
}
dfs_1(root,-1,0);
dfs_2(root,root);
tree.init(n,dfs_w);
while(q--){
opt=get_char();
x=read_int();y=read_int();
if(opt=='C')
update_path(x,y,read_int());
else
enter(query_path(x,y));
}
return 0;
}