旅行[樹剖][線段樹動態開點]
題目描述
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事件,輸出一行,表示旅行者記下的數字。
輸入樣例#1:
5 6 3 1 2 3 1 2 3 3 5 1 1 2 1 3 3 4 3 5 QS 1 5 CC 3 1 QS 1 5 CW 3 3 QS 1 5 QM 2 4
輸出樣例#1:
8 9 11 3
N,Q < =10^5 , C < =10^5
資料保證對所有QS和QM事件,起點和終點城市的信仰相同;在任意時
刻,城市的評級總是不大於10^4的正整數,且宗教值不大於C。
每一種宗教存一棵線段樹,動態開點加上樹剖就可以了
空間O(c*logn) 時間O(nlogn)
#include<bits/stdc++.h>
#define N 100005
#define M N*40
using namespace std;
int first[N],next[N*2],to[N*2],tot;
int w[N],c[N],n,m,cnt;
struct Node{int l,r,val,Max;}t[M];
int rt[N],pre[N]; char s[5];
int fa[N],dep[N],top[N],sign;
int size[N],id[N],son[N];
int read(){
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
return cnt*f;
}
/*-----------------------------dfs-----------------------------------*/
void add(int x,int y){
next[++tot]=first[x],first[x]=tot,to[tot]=y;
}
void dfs1(int u,int f){
size[u]=1;
for(int i=first[u];i;i=next[i]){
int t=to[i]; if(t==f) continue;
fa[t]=u,dep[t]=dep[u]+1;
dfs1(t,u); size[u]+=size[t];
if(size[t]>size[son[u]]) son[u]=t;
}
}
void dfs2(int u,int Top){
id[u]=++sign , top[u]=Top , pre[sign]=u;
if(son[u]) dfs2(son[u],Top);
for(int i=first[u];i;i=next[i]){
int t=to[i];
if(t!=fa[u]&&t!=son[u]) dfs2(t,t);
}
}
/*---------------------------線段樹--------------------------------*/
void Pushup(int o){
t[o].Max = max(t[t[o].l].Max , t[t[o].r].Max);
t[o].val = t[t[o].l].val + t[t[o].r].val;
}
void Insert(int &o,int l,int r,int pos,int val){
if(!o) o=++cnt;
if(l==r){t[o].val = t[o].Max = val;return;}
int mid=(l+r)>>1;
if(pos<=mid) Insert(t[o].l,l,mid,pos,val);
else Insert(t[o].r,mid+1,r,pos,val);
Pushup(o);
}
void Delete(int &o,int l,int r,int pos){
if(!o) return;
if(l==r){t[o].val = t[o].Max = 0;return;}
int mid=(l+r)>>1;
if(pos<=mid) Delete(t[o].l,l,mid,pos);
else Delete(t[o].r,mid+1,r,pos);
Pushup(o);
}
int quary_val(int o,int l,int r,int L,int R){
if(L<=l && r<=R) return t[o].val;
int mid=(l+r)>>1 , ans=0;
if(L<=mid) ans+=quary_val(t[o].l,l,mid,L,R);
if(R>mid) ans+=quary_val(t[o].r,mid+1,r,L,R);
return ans;
}
int quary_Max(int o,int l,int r,int L,int R){
if(L<=l && r<=R) return t[o].Max;
int mid=(l+r)>>1 , ans=0;
if(L<=mid) ans = max(ans , quary_Max(t[o].l,l,mid,L,R));
if(R>mid) ans = max(ans , quary_Max(t[o].r,mid+1,r,L,R));
return ans;
}
/*-------------------------------樹剖--------------------------------*/
int Quary_val(int x,int y){
int ans=0 , Color=c[x];
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans += quary_val(rt[Color],1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
ans += quary_val(rt[Color],1,n,id[y],id[x]);
return ans;
}
int Quary_Max(int x,int y){
int ans=0 , Color=c[x];
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans = max(ans , quary_Max(rt[Color],1,n,id[top[x]],id[x]));
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
ans = max(ans , quary_Max(rt[Color],1,n,id[y],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;i<n;i++){
int x=read(),y=read();
add(x,y),add(y,x);
}
dep[1]=1 , dfs1(1,0) , dfs2(1,1);
for(int i=1;i<=n;i++){
Insert(rt[c[pre[i]]],1,n,i,w[pre[i]]);
}
while(m--){
scanf("%s",s);
int x=read(),y=read();
if(s[1]=='C'){
Delete(rt[c[x]],1,n,id[x]);
c[x]=y;
Insert(rt[c[x]],1,n,id[x],w[x]);
}
if(s[1]=='W'){
Delete(rt[c[x]],1,n,id[x]);
w[x]=y;
Insert(rt[c[x]],1,n,id[x],w[x]);
}
if(s[1]=='S') printf("%d\n",Quary_val(x,y));
if(s[1]=='M') printf("%d\n",Quary_Max(x,y));
}
}