样例的输出全是 1
,用的是线段树+树剖,求调。
#include <iostream>
#include <vector>
#include <tuple>
#define fswap(x,y) x^=y^=x^=y // <=> swap(x,y)
using namespace std;
using cint= const int;
static cint N=100001;
struct info { // 维护线段树上的区间信息
int val,lft,rit; // 分别表示 颜色段数量,左端点,右端点
info(cint val,cint lft,cint rit): val(val),lft(lft),rit(rit) {}
info(cint val=0): val(1),lft(val),rit(val) {}
info operator +(const info &o) const { // 合并序列
if(!val) return o;
else if(!o.val) return *this;
else return info(val+o.val-(rit==o.lft?1:0),lft,o.rit);
}
inline info reverse() { // 反转序列
fswap(lft,rit);
return *this;
}
};
class segment_tree { // 区间赋值,查询颜色段数量的线段树
info val[N<<2];
int n,*a,tag[N<<2];
void __build(cint u,cint l,cint r) {
if(l==r) {val[u]=a[l];return;}
cint mid=(l+r)>>1;
__build(u<<1,l,mid);
__build(u<<1|1,mid+1,r);
val[u]=val[u<<1]+val[u<<1|1];
}
void __apply(cint u,cint l,cint r,cint x) {
if(x>=0)
tag[u]=x,val[u]=x;
}
void __pushdown(cint u,cint l,cint r) {
if(tag[u]) {
cint mid=(l+r)>>1;
__apply(u<<1,l,mid,tag[u]);
__apply(u<<1|1,mid+1,r,tag[u]);
tag[u]=-1;
}
}
void __upd(cint u,cint l,cint r,cint s,cint t,cint x) {
if(s<=l&&r<=t) {__apply(u,l,r,x);return;}
__pushdown(u,l,r);
cint mid=(l+r)>>1;
if(s<=mid) __upd(u<<1,l,mid,s,t,x);
if(t>mid) __upd(u<<1|1,mid+1,r,s,t,x);
val[u]=val[u<<1]+val[u<<1|1];
}
info __query(cint u,cint l,cint r,cint s,cint t) {
if(s<=l&&r<=t) return val[u];
cint mid=(l+r)>>1;
__pushdown(u,l,r);
if(t<=mid) return __query(u<<1,l,mid,s,t);
if(s>mid) return __query(u<<1|1,mid+1,r,s,t);
return __query(u<<1,l,mid,s,t)+__query(u<<1|1,mid+1,r,s,t);
}
public:
segment_tree(cint n=0,int *a=nullptr): n(n),a(a) {
if(a) __build(1,1,n);
}
inline void resize(cint __n,int *__a) {
n=__n,a=__a;
__build(1,1,n);
for(int &i: tag)
i=-1;
}
inline void upd(cint s,cint t,cint x) {
__upd(1,1,n,s,t,x);
}
inline info query(cint s,cint t) {
return __query(1,1,n,s,t).val;
}
};
segment_tree st;
vector<int> g[N]; // vector 存树
int n,m,clk,sz[N],dep[N],top[N],fa[N],son[N],dfn[N];
// sz[]:子树大小;dep[]:结点深度;top[]:结点对应的链顶;fa[]:父节点;son[]重子节点;dfn[]重边优先遍历的dfs序
void dfs1(cint u) { // 求 dep[],sz[],fa[],son[]
sz[u]=1;
for(auto v: g[u])
if(v!=fa[u]) {
dep[v]=dep[u]+1,
fa[v]=u;
dfs1(v);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void bui(cint u,cint t) { // 求 dfn[],top[]
dfn[u]=++clk,top[u]=t;
if(son[u]) bui(son[u],t);
for(auto v: g[u])
if(v!=fa[u]&&v!=son[u])
bui(v,v);
}
int arr[N],a[N];
void paint(int u,int v,int w) { // 染色
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) fswap(u,v);
st.upd(dfn[top[u]],dfn[u],w);
u=fa[top[u]];
}
if(dep[u]<dep[v]) fswap(u,v);
st.upd(dfn[v],dfn[u],w);
}
int cnt(int u,int v) { // 统计答案
info x(0,0,0),y(0,0,0);
while(top[u]!=top[v]) {
if(dep[top[u]]>dep[top[v]]) x=st.query(dfn[top[u]],dfn[u])+x,u=fa[top[u]];
else y=st.query(dfn[top[v]],dfn[v])+y,v=fa[top[v]];
}
if(dep[u]>dep[v]) x=st.query(dfn[v],dfn[u])+x;
else y=st.query(dfn[u],dfn[v])+y;
return (x.reverse()+y).val;
}
void init(cint root) { // 树剖
dfs1(root);
bui(root,root);
for(int i=1;i<=n;i++)
arr[dfn[i]]=a[i];
st.resize(n,arr);
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false),
cout.tie(nullptr);
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int u,v,w,i=1;i<n;i++) {
cin>>u>>v;
g[u].push_back(v),
g[v].push_back(u);
}
init(1);
string op;
for(int a,b,c;m--;) {
cin>>op>>a>>b;
if(op=="C") {
cin>>c;
paint(a,b,c);
} else {
cout<<cnt(a,b)<<'\n';
}
}
return 0;
}