S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足
从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教,
S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
在S国的历史上常会发生以下几种事件:
”CC x c”:城市x的居民全体改信了c教;
”CW x w”:城市x的评级调整为w;
”QS x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过
的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
输入的第一行包含整数N,Q依次表示城市数和事件数。
接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的
评级和信仰。
接下来N-1行每行两个整数x,y表示一条双向道路。
接下来Q行,每行一个操作,格式如上所述。
对每个QS和QM事件,输出一行,表示旅行者记下的数字。
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cctype>
#define im int mid = (l + r) >> 1
using namespace std;
const int N = 200000;
int son[N],siz[N],fa[N],top[N],dep[N];
int idx[N],cnt2;
int to[N<<1],next[N<<1],val[N],head[N],b[N],cnt1;
int n,m;
int tr[N],
ls[((N<<3)+(N<<1))<<1],
rs[((N<<3)+(N<<1))<<1],
sum[((N<<3)+(N<<1))<<1],
maxn[((N<<3)+(N<<1))<<1];
class ReadIn {
private:
inline char nc() {
static char buf[100000], *p1, *p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
public:
inline int read() {
int x=0;char ch=nc();
while(!isdigit(ch))ch=nc();
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-‘0‘;ch=nc();}
return x;
}
inline char getc() {
char ch=nc();
while(isspace(ch))ch=nc();
return ch;
}
}Rd;
class SegmentTree {
public :
void change(int l,int r,int x,int y,int &p) {
if(!p)p=++cnt2;
if(l==r) {
maxn[p]=sum[p]=y;
return;
}
int mid = (l+r) >> 1;
if(x<=mid) change(l,mid,x,y,ls[p]);
else change(mid+1,r,x,y,rs[p]);
sum[p]=sum[ls[p]]+sum[rs[p]];
maxn[p]=max(maxn[ls[p]],maxn[rs[p]]);
}
int qsum(int l,int r,int x,int y,int &p) {
if(!p)return 0;
if(x<=l&&r<=y) {
return sum[p];
}
int mid= (l+r) >> 1;
int re = 0;
if(x<=mid) re+=qsum(l,mid,x,y,ls[p]);
if(y>mid) re+=qsum(mid+1,r,x,y,rs[p]);
return re;
}
int qmax(int l,int r,int x,int y,int &p) {
if(!p)return 0;
if(x<=l&&r<=y) {
return maxn[p];
}
int mid= (l+r) >> 1;
int re = 0;
if(x<=mid) re=max(re,qmax(l,mid,x,y,ls[p]));
if(y>mid) re=max(re,qmax(mid+1,r,x,y,rs[p]));
return re;
}
}Tr;
class TreeChainDissection {
public :
void dfs1(int p) {
dep[p]=dep[fa[p]]+1;
siz[p]=1;
for (int i = head[p];i; i = next[i] ) {
if(to[i] != fa[p]) {
fa[to[i]]=p;
dfs1(to[i]);
siz[p]+=siz[to[i]];
if(siz[to[i]]>siz[son[p]])
son[p]=to[i];
}
}
}
void dfs2(int p,int t) {
idx[p]=++cnt2;
top[p]=t;
if(son[p]) dfs2(son[p],t);
for(int i=head[p];i;i=next[i])
if(to[i]!=fa[p]&&to[i]!=son[p])
dfs2(to[i],to[i]);
}
int lcas(int x,int y) {
int re = 0, root = b[x];
while(top[x] != top[y]) {
if(dep[top[x]]>dep[top[y]]) swap(x,y);
re+=Tr.qsum(1,n,idx[top[y]],idx[y],tr[root]);
y=fa[top[y]];
}
if(dep[x]<dep[y])swap(x,y);
re+=Tr.qsum(1,n,idx[y],idx[x],tr[root]);
return re;
}
int lcam(int x,int y) {
int re=0, root = b[x];
while(top[x]!=top[y]) {
if(dep[top[x]]>dep[top[y]]) swap(x,y);
re = max(re,Tr.qmax(1,n,idx[top[y]],idx[y],tr[root]));
y=fa[top[y]];
}
if(dep[x]<dep[y])swap(x,y);
re = max(re,Tr.qmax(1,n,idx[y],idx[x],tr[root]));
return re;
}
}Tcd;
class Pre {
private :
inline void add_edge(int a,int b) {
to[++cnt1] = b;
next[cnt1] = head[a];
head[a] = cnt1;
to[++cnt1] = a;
next[cnt1] = head[b];
head[b] = cnt1;
}
public :
void init() {
n=Rd.read(),m=Rd.read();
int i,x,y;
for(i=1 ;i <=n; i++) val[i] = Rd.read(),b[i] = Rd.read();
for(i=1 ;i < n; i++) {
x=Rd.read(),y=Rd.read();
add_edge(x,y);
}
Tcd.dfs1(1);
Tcd.dfs2(1,1);
for(i=1 ;i <=n; i++) {
Tr.change(1,n,idx[i],val[i],tr[b[i]]);
}
}
}Pr;
void solve() {
int i,x,y;
char opt;
for(i=1;i<=m;i++) {
opt=Rd.getc();
opt=Rd.getc();
x = Rd.read();
y = Rd.read();
if(opt==‘C‘) {
Tr.change(1,n,idx[x],0,tr[b[x]]);
b[x]=y;
Tr.change(1,n,idx[x],val[x],tr[b[x]]);
}
else if(opt==‘S‘){
int ans=Tcd.lcas(x,y);
printf("%d\n",ans);
}
else if(opt==‘W‘) {
Tr.change(1,n,idx[x],y,tr[b[x]]);
val[x] = y;
}
else {
int ans=Tcd.lcam(x,y);
printf("%d\n", ans);
}
}
}
int main() {
Pr.init();
solve();
}