题解
先考虑比较特殊的情况:如果A和B在一个点双内,那么答案就是这个点双的最小值。否则,考虑对点双缩点构建圆方树,于是A到B中经过的每一个方点都代表由这个点双的一个点进入,另一个点出来,这样一定可以取到这个点双的最小值,于是把方点的权值设为这个点双的最小值。这样,答案就是路径的最小值了,树剖维护即可。
剩下的问题在于动态维护方点的权值,如果直接做在修改时把所有连边改一遍效率会炸,考虑利用树的形态:每个方点只取它的儿子的最小值,这样修改一个点只会修改到它的父亲,查询的时候,不在顶点上的方点会被父亲算到,如果顶点是方点就再算一次它的父亲,用multiset
维护每个方点的儿子的值,效率
O
(
n
l
o
g
2
n
)
O(nlog^{2}n)
O(nlog2n)。
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5,F=1e9+5;
int n,m; vector<int>h[N];
int q[N],t,dn[N],lw[N],ct;
int pt,w[N],hd[N],to[N],nx[N],tt;
multiset<int>st[N];
void add(int u,int v){
//cout<<u<<" "<<v<<endl;
nx[++tt]=hd[u]; to[hd[u]=tt]=v;
}
void dfs(int u,int fa){ //cout<<u<<" "<<fa<<endl;
dn[u]=lw[u]=++ct; q[++t]=u;
int z=h[u].size();
for(int i=0;i<z;i++){
int v=h[u][i];
if(!dn[v]){
dfs(v,u);
if(lw[v]>=dn[u]){
pt++;
while(q[t]!=v) add(q[t],pt),add(pt,q[t]),t--;
add(q[t],pt),add(pt,q[t]),t--;
add(u,pt),add(pt,u);
}
lw[u]=min(lw[u],lw[v]);
}
else if(v!=fa) lw[u]=min(lw[u],dn[v]);
}
}
int fa[N],dp[N],sz[N],sn[N],tp[N],id[N];
void cnt(int u){
multiset<int>:: iterator it=st[u].begin();
w[u]=(*it);
}
void d1(int u){
sz[u]=1;
for(int e=hd[u];e;e=nx[e]) if(to[e]!=fa[u]){
int v=to[e]; fa[v]=u; dp[v]=dp[u]+1;
d1(v); sz[u]+=sz[v];
if(sz[v]>sz[sn[u]]) sn[u]=v;
if(u>pt) st[u].insert(w[v]);
}
if(u>pt) cnt(u);
}
void d2(int u){
dn[u]=++ct; id[ct]=u;
if(sn[u]) tp[sn[u]]=tp[u],d2(sn[u]);
for(int e=hd[u];e;e=nx[e]){
int v=to[e];
if(v==fa[u] || v==sn[u]) continue;
tp[v]=v; d2(v);
}
}
#define mid ((l+r)>>1)
#define lc (u<<1)
#define rc ((u<<1)|1)
int mn[N<<2];
void bld(int u,int l,int r){
if(l==r){
mn[u]=w[id[l]]; return;
}
bld(lc,l,mid); bld(rc,mid+1,r);
mn[u]=min(mn[lc],mn[rc]);
}
void upd(int u,int l,int r,int x){
if(l==r){
mn[u]=w[id[l]]; return;
}
if(x<=mid) upd(lc,l,mid,x);
else upd(rc,mid+1,r,x);
mn[u]=min(mn[lc],mn[rc]);
}
int qry(int u,int l,int r,int a,int b){
//if(u==1) printf("%d %d\n",a,b);
if(a<=l && r<=b) return mn[u];
int mi=F;
if(a<=mid) mi=qry(lc,l,mid,a,b);
if(b>mid) mi=min(mi,qry(rc,mid+1,r,a,b));
return mi;
}
int main()
{
srand(time(0));
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
int T; cin>>n>>m>>T;
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int u,v,i=1;i<=m;i++)
scanf("%d%d",&u,&v),h[u].push_back(v),h[v].push_back(u);
pt=n; dfs(1,0); swap(n,pt); //return 0;
ct=0; dp[1]=1; d1(1); ///return 0;
tp[1]=1; d2(1); //return 0;
bld(1,1,n);
while(T--){
int a,b; char c; scanf(" %c %d%d",&c,&a,&b);
if(c=='C'){
int f=fa[a];
if(f){
st[f].erase(w[a]); st[f].insert(b);
cnt(f); upd(1,1,n,dn[f]);
}
w[a]=b; upd(1,1,n,dn[a]);
}
else{
int mn=1e9;
while(tp[a]!=tp[b]){
if(dp[tp[a]]<dp[tp[b]]) swap(a,b);
mn=min(mn,qry(1,1,n,dn[tp[a]],dn[a]));
a=fa[tp[a]];
}
//cout<<"mn="<<mn<<endl;
if(dp[a]>dp[b]) swap(a,b);
if(a>pt && fa[a]) mn=min(mn,w[fa[a]]);
mn=min(mn,qry(1,1,n,dn[a],dn[b]));
printf("%d\n",mn);
}
}
return 0;
}
/*
3 3 3
1
2
3
1 2
2 3
1 3
A 2 3
C 1 5
A 2 3
*/