传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1036
以前用链剖写过,感觉块状树确实好写,常数小的sqrt(n)比常数大的log^2n大不了多少
Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
vector<int>G[maxn],Ge[maxn];
int cnt,sqrtn,n,m;
int w[maxn],sum[maxn],mx[maxn],fa[maxn],dep[maxn],bel[maxn],siz[maxn];
void dfs(int u){
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(v==fa[u])continue;
fa[v]=u;dep[v]=dep[u]+1;
if(siz[bel[u]]<sqrtn){
siz[bel[u]]++;bel[v]=bel[u];
Ge[u].push_back(v);
}dfs(v);
}
}
void dfs(int u,int s,int maxx){
s+=w[u];sum[u]=s;
maxx=max(maxx,w[u]);mx[u]=maxx;
for(int i=0;i<Ge[u].size();i++)dfs(Ge[u][i],s,maxx);
}
void Change(int u,int ww){
w[u]=ww;if(bel[u]==u)dfs(u,0,INT_MIN);
else dfs(u,sum[fa[u]],mx[fa[u]]);
}
pair<int,int> qsumax(int u,int v){
int s=0,maxx=INT_MIN;
while(u!=v){
if(dep[u]<dep[v])swap(u,v);
if(bel[u]==bel[v]){
s+=w[u];maxx=max(maxx,w[u]);
u=fa[u];
}else{
if(dep[bel[u]]<dep[bel[v]])swap(u,v);
s+=sum[u],maxx=max(maxx,mx[u]);
u=fa[bel[u]];
}
}s+=w[u],maxx=max(maxx,w[u]);
return pair<int,int>(s,maxx);
}
int main(){
scanf("%d",&n);
sqrtn=sqrt(n);
for(int i=1;i<n;i++){
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}for(int i=1;i<=n;i++)scanf("%d",w+i),bel[i]=i,siz[i]=1;
dfs(1);
for(int i=1;i<=n;i++)if(bel[i]==i)
dfs(i,0,INT_MIN);
int q;scanf("%d",&q);
while(q--){
int x,y;
char op[5];scanf("%s",op);scanf("%d%d",&x,&y);
if(op[0]=='C'){
Change(x,y);
}else{
pair<int,int>anss=qsumax(x,y);
if(op[1]=='M')
printf("%d\n",anss.second);
else
printf("%d\n",anss.first);
}
}
return 0;
}