#include<cstdio>
#include <iostream>
using namespace std;
int read(){
int x=0 ,f=1 ;char ch=getchar();
while (ch<' 0 ' ||ch>' 9 ' ) ch=getchar();
while (ch>=' 0 ' &&ch<=' 9 ' ){x=x*10 +ch-' 0 ' ;ch=getchar();}
return x;
}
const int N=1e5+5 ,M=1e7+5 ;
struct node{
int v,next;
}e[N <<1 ];
int n,m,sz,cnt,tot,w[N],c[N],fa[N],id[N],dep[N],siz[N],son[N],top[N],head[N];
int root[N],ls[M],rs[M],mx[M],sum[M];
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;
}
// ===========================================================预处理
void updata(int k){
mx[k] =max(mx[ls[k]],mx[rs[k]]);
sum[k] =sum[ls[k]]+sum[rs[k]];
}
void insert(int &k,int l,int r,int pos,int val){
if (!k) k=++sz;
if (l==r){sum[k]=mx[k]=val;return ;}
int mid=l+r>>1 ;
if (pos<=mid) insert(ls[k],l,mid,pos,val);
else insert(rs[k],mid+1 ,r,pos,val);
updata(k);
}
int Q_sum(int k,int l,int r,int x,int y){
if (!k) return 0 ;
if (l==x&&r==y) return sum[k];
int mid=l+r>>1 ;
if (y<=mid) return Q_sum(ls[k],l,mid,x,y);
else if (x>mid) return Q_sum(rs[k],mid+1 ,r,x,y);
else return Q_sum(ls[k],l,mid,x,mid)+Q_sum(rs[k],mid+1 ,r,mid+1 ,y);
}
int Q_max(int k,int l,int r,int x,int y){
if (!k) return 0 ;
if (l==x&&r==y) return mx[k];
int mid=l+r>>1 ;
if (y<=mid) return Q_max(ls[k],l,mid,x,y);
else if (x>mid) return Q_max(rs[k],mid+1 ,r,x,y);
else return max(Q_max(ls[k],l,mid,x,mid),Q_max(rs[k],mid+1 ,r,mid+1 ,y));
}
// ===================================动态插点的线段树,不要当成主席树
void dfs(int x,int f,int de){
fa[x] =f;dep[x]=de;siz[x]=1 ;
for (int i=head[x],v;i;i=e[i].next){
if ((v=e[i].v)!=f){
dfs(v,x,de +1 );
siz[x] +=siz[v];
if (!son[x]||siz[son[x]]<siz[v]) son[x]=v;
}
}
}
void getpos(int u,int tp){
top[u] =tp;
id[u] =++sz;
if (!son[u]) return ;
getpos(son[u],tp);
for (int i=head[u],v;i;i=e[i].next){
v =e[i].v;
if (v!=son[u]&&v!=fa[u]){
getpos(v,v);
}
}
}
int lca(int x,int y){
for (;top[x]!=top[y];x=fa[top[x]]){
if (dep[top[x]]<dep[top[y]]) swap(x,y);
}
return dep[x]<dep[y]?x:y;
}
int query_sum(int c,int x,int f){
int ans=0 ;
for (;top[x]!=top[f];x=fa[top[x]]){
ans +=Q_sum(root[c],1 ,n,id[top[x]],id[x]);
}
ans +=Q_sum(root[c],1 ,n,id[f],id[x]);
return ans;
}
int query_max(int c,int x,int f){
int ans=0 ;
for (;top[x]!=top[f];x=fa[top[x]]){
ans =max(ans,Q_max(root[c],1 ,n,id[top[x]],id[x]));
}
ans =max(ans,Q_max(root[c],1 ,n,id[f],id[x]));
return ans;
}
// ==========================================================树链剖分
int main(){
n =read();m=read();
for (int i=1 ;i<=n;i++) w[i]=read(),c[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 );
for (int i=1 ;i<=n;i++) insert(root[c[i]],1 ,n,id[i],w[i]);
for (int i=1 ,x,y;i<=m;i++){
char s[6 ];scanf(" %s " ,s);x=read();y=read();
if (s[0 ]==' C ' ){
if (s[1 ]==' C ' ){
insert(root[c[x]], 1 ,n,id[x],0 );
insert(root[c[x] =y],1 ,n,id[x],w[x]);
}
else {
insert(root[c[x]], 1 ,n,id[x],w[x]=y);
}
}
else {
int f=lca(x,y);
if (s[1 ]==' S ' ){
int t=query_sum(c[x],x,f)+query_sum(c[x],y,f);
if (c[x]==c[f]) t-=w[f];
printf( " %d\n " ,t);
}
else {
printf( " %d\n " ,max(query_max(c[x],x,f),query_max(c[x],y,f)));
}
}
}
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应用必不可少的技术