http://www.lydsy.com/JudgeOnline/showsource.php?id=2443124
树链剖分套线段树直接肝
注意合并过程
#include<cstdio>
#include<algorithm>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
#define gc getchar()
using std::swap;
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
const int N=800011;
char S[5];
int c[N];
int n,m,dfn_num,x,y,z;
inline int read(){
char c;while(c=gc,c==' '||c=='\n');int data=c-48;
while(c=gc,c>='0'&&c<='9')data=(data<<1)+(data<<3)+c-48;return data;
}
struct edge{
int to;
edge *nxt;
#define to(it) it->to
#define add(x,y) (*++et=(edge){y,las[x]},las[x]=et)
#define VIS(now) for(edge *it=las[now];it;it=it->nxt)
}e[N],*las[N],*et=e;
namespace Segment_Tree{
struct Tree{
int lc,rc,sum,tag;
}tr[N];
inline void push_up(int k){
tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;
tr[k].lc=tr[k<<1].lc;tr[k].rc=tr[k<<1|1].rc;
if(tr[k<<1].rc==tr[k<<1|1].lc)--tr[k].sum;
}
inline void push_down(int k){
if(!tr[k].tag)return;
tr[k<<1].lc=tr[k<<1].rc=tr[k<<1|1].lc=tr[k<<1|1].rc=tr[k<<1].tag=tr[k<<1|1].tag=tr[k].tag;
tr[k<<1].sum=tr[k<<1|1].sum=1;
tr[k].tag=0;
}
inline void change(int k,int x,int y,int v,int l=1,int r=n){
push_down(k);
if(x<=l&&r<=y){
tr[k].sum=1;
tr[k].tag=tr[k].lc=tr[k].rc=v;
return;
}
int mid=(l+r)>>1;
if(x<=mid)change(k<<1,x,y,v,l,mid);
if(mid<y)change(k<<1|1,x,y,v,mid+1,r);
push_up(k);
}
inline int query(int k,int x,int y,int l=1,int r=n){
push_down(k);
push_up(k);
if(x<=l&&r<=y)return tr[k].sum;
int mid=(l+r)>>1,ans=0;
if(x<=mid)ans+=query(k<<1,x,y,l,mid);
if(mid<y)ans+=query(k<<1|1,x,y,mid+1,r);
if(x<=mid&&mid<y&&tr[k<<1].rc==tr[k<<1|1].lc)--ans;
return ans;
}
inline int query_color(int k,int pos,int l=1,int r=n){
push_down(k);
push_up(k);
if(l==r)return tr[k].lc;
int mid=(l+r)>>1;
return pos<=mid?query_color(k<<1,pos,l,mid):query_color(k<<1|1,pos,mid+1,r);
}
};
using namespace Segment_Tree;
namespace TCP{
int dep[N],sz[N],fa[N];
int top[N],xu[N];
inline void dfs1(int now){
sz[now]=1;
VIS(now)
if(!dep[to(it)]){
dep[to(it)]=dep[now]+1;fa[to(it)]=now;
dfs1(to(it));sz[now]+=sz[to(it)];
}
}
inline void dfs2(int now,int chain){
register int i=0;
top[now]=chain;xu[now]=++dfn_num;
change(1,xu[now],xu[now],c[now]);
VIS(now)if(dep[to(it)]>dep[now]&&sz[i]<sz[to(it)])i=to(it);
if(!i)return;
dfs2(i,chain);
VIS(now)if(dep[to(it)]>dep[now]&&to(it)!=i)dfs2(to(it),to(it));
}
inline int up_query(int x,int y){
int ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans+=query(1,xu[top[x]],xu[x]);
if(query_color(1,xu[top[x]])==query_color(1,xu[fa[top[x]]]))--ans;
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
ans+=query(1,xu[x],xu[y]);
return ans;
}
inline void up_change(int x,int y,int z){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
change(1,xu[top[x]],xu[x],z);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
change(1,xu[x],xu[y],z);
}
};
using namespace TCP;
int main(){
n=read();m=read();
FOR(i,1,n)c[i]=read()+1;
FOR(i,2,n){
x=read();y=read();
add(x,y);add(y,x);
}
dep[1]=1;dfs1(1);dfs2(1,1);
while(m--){
scanf("%s",S);
x=read();y=read();
if(S[0]=='Q')
printf("%d\n",up_query(x,y));
else{
z=read()+1;
up_change(x,y,z);
}
}
return 0;
}