/*
维护:
lcol(当前区间左端点的颜色)
rcol(当前区间右端点的颜色)
sum(当前区间颜色段数量)
合并:
sum=lson.sum+rson.sum-1{lson.rcol==rson.lcol}
sum=lson.sum+rson.sum{lson.rcol!=rson.lcol}
*/
#include<cstdio>
#include<iostream>
#define lc k<<1
#define rc k<<1|1
#define O3 __attribute__((optimize("O3")))
#define IN inline
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
char in(){
for(char ch=getchar();;ch=getchar()) if(ch>='A'&&ch<='Z') return ch;
}
const int M=1e5+5,N=M<<2;
struct sgt{int lcol,rcol,sum,tag;}tr[N];
struct edge{int v,next;}e[N];
int n,m,tot,cnt,head[M],pos[M],dfn[M],val[M],son[M],top[M],dep[M],fa[M],siz[M];
IN void add(int x,int y){
e[++tot].v=y;e[tot].next=head[x];head[x]=tot;
e[++tot].v=x;e[tot].next=head[y];head[y]=tot;
}
O3 void dfs(int x,int f,int de){
fa[x]=f;dep[x]=de;siz[x]=1;
for(int i=head[x];i;i=e[i].next){
if(e[i].v!=f){
dfs(e[i].v,x,de+1);
siz[x]+=siz[e[i].v];
if(!son[x]||siz[son[x]]<siz[e[i].v]) son[x]=e[i].v;
}
}
}
O3 void getpos(int x,int t1){
top[x]=t1;pos[x]=++cnt;dfn[cnt]=x;
if(!son[x]) return ;
getpos(son[x],t1);
for(int i=head[x];i;i=e[i].next){
if(son[x]!=e[i].v&&fa[x]!=e[i].v){
getpos(e[i].v,e[i].v);
}
}
}
//=====================================================预处理
IN void updata(int k){
tr[k].lcol=tr[lc].lcol;
tr[k].rcol=tr[rc].rcol;
tr[k].sum=tr[lc].sum+tr[rc].sum-(tr[lc].rcol==tr[rc].lcol);
}
IN void pushdown(int k){
if(!tr[k].tag) return ;
tr[lc].lcol=tr[lc].rcol=tr[k].tag;
tr[rc].lcol=tr[rc].rcol=tr[k].tag;
tr[lc].tag=tr[rc].tag=tr[k].tag;
tr[lc].sum=tr[rc].sum=1;
tr[k].tag=0;
}
O3 void build(int k,int l,int r){
if(l==r){
tr[k].lcol=tr[k].rcol=val[dfn[l]];
tr[k].sum=1;
return ;
}
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
updata(k);
}
O3 void change(int k,int l,int r,int x,int y,int v){
if(l==x&&r==y){
tr[k].sum=1;
tr[k].lcol=tr[k].rcol=tr[k].tag=v;
return ;
}
int mid=l+r>>1;
pushdown(k);
if(y<=mid) change(lc,l,mid,x,y,v);
else if(x>mid) change(rc,mid+1,r,x,y,v);
else change(lc,l,mid,x,mid,v),change(rc,mid+1,r,mid+1,y,v);
updata(k);
}
O3 int query(int k,int l,int r,int x,int y){
if(l==x&&r==y) return tr[k].sum;
pushdown(k);
int mid=l+r>>1;
if(y<=mid) return query(lc,l,mid,x,y);
else if(x>mid) return query(rc,mid+1,r,x,y);
else{
int res=query(lc,l,mid,x,mid)+query(rc,mid+1,r,mid+1,y);
if(tr[lc].rcol==tr[rc].lcol) res--;
return res;
}
}
O3 int ask_l(int k,int l,int r,int x){
if(l==r) return tr[k].lcol;
pushdown(k);
int mid=l+r>>1;
if(x<=mid) return ask_l(lc,l,mid,x);
else return ask_l(rc,mid+1,r,x);
}
//=====================================================线段树
IN void modify(int x,int y,int c){
for(;top[x]!=top[y];x=fa[top[x]]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
change(1,1,n,pos[top[x]],pos[x],c);
}
//if(x==y) return ;1W
if(dep[x]>dep[y]) swap(x,y);
change(1,1,n,pos[x],pos[y],c);
}
IN int find(int x,int y){
int nc,fc,ans=0;
for(;top[x]!=top[y];x=fa[top[x]]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=query(1,1,n,pos[top[x]],pos[x]);
nc=ask_l(1,1,n,pos[top[x]]);
fc=ask_l(1,1,n,pos[fa[top[x]]]);
if(nc==fc) ans--;
}
//if(x==y) return ans;2W
if(dep[x]>dep[y]) swap(x,y);
ans+=query(1,1,n,pos[x],pos[y]);
if(!ans) ans++;
return ans;
}
//=====================================================树链剖分
int main(){
n=read();m=read();
for(int i=1;i<=n;i++) val[i]=read();
for(int i=1,x,y;i<n;i++){
x=read();y=read();
add(x,y);
}
dfs(1,1,1);
getpos(1,1);
build(1,1,n);
for(int i=1,a,b,c;i<=m;i++){
c=in();
if(c=='C'){
a=read();b=read();c=read();
modify(a,b,c);
}
else{
a=read();b=read();
printf("%d\n",find(a,b));
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术