·· / ·– ·· ·-·· ·-·· / ·–· · ·-· ··· ·· ··· - / ··- -· - ·· ·-·· / ·· / ·– ·· -·
題目來源:http://www.lydsy.com/JudgeOnline/problem.php?id=3531
這是一道非常有價值的樹剖。
對於每個飛天麪條神教,建立一顆線段樹進行維護,查詢時,在對應的飛天麪條神教對應的線段樹進行查詢。
如果一個城市信了其他的飛天麪條神教,那麼把它從自己的麪條神教對應的線段樹中抹去,再在新麪條教的線段樹中加上權值。
c <= 100000 真的不會爆嗎?
不會,因爲這裏的線段樹是動態加點的。
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=110000,M=10000009;
int size[N],son[N],fa[N],dep[N],w[N],top[N],id[M];
int ls[M],rs[M],mx[M],sum[M],root[N];
int ver[N<<1],nxt[N<<1],head[N];
int ww[N],cc[N];
int n,m,cnt=0,tot=1,ne=0;
int read () {
int x=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x;
}
void add (int u,int v) {
ver[++tot]=v;nxt[tot]=head[u];head[u]=tot;
}
void dfs_1 (int u,int from) {
size[u]=1;son[u]=0;fa[u]=from;
for (int i=head[u];i;i=nxt[i]) {
int v=ver[i];
if (v==fa[u]) continue;
dep[v]=dep[u]+1; fa[v]=u;
dfs_1(v,u);size[u]+=size[v];
if (!son[u]||size[son[u]]<size[v]) son[u]=v;
}
}
void dfs_2 (int u,int st) {
w[u]=++cnt;top[u]=st;id[cnt]=u;
if (son[u]) dfs_2(son[u],st);
for (int i=head[u];i;i=nxt[i]) {
int v=ver[i];
if (v==son[u]||v==fa[u]) continue;
dfs_2(v,v);
}
}
void update (int x) {
mx[x]=max(mx[ls[x]],mx[rs[x]]);
sum[x]=sum[ls[x]]+sum[rs[x]];
}
void change (int &k,int l,int r,int x,int num) {
if (!k) k=++ne;//動態加點
if (l==r) { mx[k]=sum[k]=num;return; }
int mid=(l+r)>>1;
if (x<=mid) change(ls[k],l,mid,x,num);
else change(rs[k],mid+1,r,x,num);
update(k);
}
int askmx (int k,int l,int r,int x,int y) {
if (!k) return 0;//防止訪問到沒拓展過的點
if (x<=l&&r<=y) return mx[k];
int ans=0,mid=(l+r)>>1;
if (x<=mid) ans=max(askmx(ls[k],l,mid,x,y),ans);
if (y>mid) ans=max(askmx(rs[k],mid+1,r,x,y),ans);
return ans;
}
int asksum (int k,int l,int r,int x,int y) {
if (!k) return 0;
if (x<=l&&r<=y) return sum[k];
int ans=0,mid=(l+r)>>1;
if (x<=mid) ans+=asksum(ls[k],l,mid,x,y);
if (y>mid) ans+=asksum(rs[k],mid+1,r,x,y);
return ans;
}
int getmx (int cc,int x,int y) {
int mx=0;
while (top[x]!=top[y]) {
if (dep[top[x]]<dep[top[y]]) swap(x,y);
mx=max(mx,askmx(root[cc],1,n,w[top[x]],w[x]));
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
mx=max(mx,askmx(root[cc],1,n,w[x],w[y]));
return mx;
}
int getsum (int cc,int x,int y) {
int sum=0;
while (top[x]!=top[y]) {
if (dep[top[x]]<dep[top[y]]) swap(x,y);
sum+=asksum(root[cc],1,n,w[top[x]],w[x]);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
sum+=asksum(root[cc],1,n,w[x],w[y]);
return sum;
}
int main () {
int u,v,x,y;
char str[5];
n=read(); m=read();
for (int i=1;i<=n;i++) ww[i]=read(),cc[i]=read();
for (int i=1;i<n;i++) {
u=read(); v=read();
add(u,v); add(v,u);
}
dfs_1(1,0); dfs_2(1,1);
for (int i=1;i<=n;i++)
change(root[cc[i]],1,n,w[i],ww[i]);
for (int i=1;i<=m;i++) {
scanf("%s",str);
x=read(); y=read();
if (str[0]=='C') {
if (str[1]=='C') {
change(root[cc[x]],1,n,w[x],0);
cc[x]=y;
change(root[cc[x]],1,n,w[x],ww[x]);
}
else change(root[cc[x]],1,n,w[x],y),ww[x]=y;
}
else {
if (str[1]=='S') printf("%d\n",getsum(cc[x],x,y));
else printf("%d\n",getmx(cc[x],x,y));
}
}
return 0;
}