求一般图两点之间所有简单路径上的点权的最小值。
我们搞出圆方树,原图两点间的所有简单路径的并就对应了圆方树上两点间路径。圆点权值为原点点权,方点权值为这个点双的权值最小值。
树链剖分维护路径最小值即可。
但是这样修改一个点的点权时可能需要修改一堆方点,复杂度会爆炸。
于是一个小trick,我们每个方点只维护儿子圆点的权值最小值。这样更改一
个点的权值时,只需要更改它的父亲方点一个即可。查询时特殊处理一下lca就好啦(如果lca是方点,那么还要考虑到这个方点的父亲的权值)。
复杂度
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,m,Q,h[N],num=0,dfn[N],low[N],dfnum=0,w[N];
int sz[N<<1],son[N<<1],top[N<<1],pos[N<<1],fa[N<<1],dep[N<<1];
struct edge{
int to,next;
}data[N<<1];
stack<int>qq;
vector<int>Son[N<<1];
struct Heap{
priority_queue<int,vector<int>,greater<int> >A,B;
inline void insert(int x){A.push(x);}
inline void erase(int x){B.push(x);}
inline int top(){
while(!B.empty()&&A.top()==B.top()) A.pop(),B.pop();
if(A.empty()) return -1;return A.top();
}
}W[N];
struct node{
int mn;
}tr[N<<3];
inline void tarjan(int x,int Fa){
dfn[x]=low[x]=++dfnum;qq.push(x);
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==Fa) continue;
if(!dfn[y]){
tarjan(y,x);low[x]=min(low[x],low[y]);
if(low[y]<dfn[x]) continue;++m;
while(1){
int z=qq.top();qq.pop();W[m-n].insert(w[z]);
Son[m].push_back(z);if(z==y) break;
}Son[x].push_back(m);
}else low[x]=min(low[x],dfn[y]);
}
}
inline void dfs1(int x){
sz[x]=1;son[x]=0;
for(int i=0;i<Son[x].size();++i){
int y=Son[x][i];fa[y]=x;dep[y]=dep[x]+1;dfs1(y);
sz[x]+=sz[y];if(sz[y]>sz[son[x]]) son[x]=y;
}
}
inline void dfs2(int x,int tp){
pos[x]=++dfnum;top[x]=tp;
if(son[x]) dfs2(son[x],tp);
for(int i=0;i<Son[x].size();++i){
int y=Son[x][i];if(y!=son[x]) dfs2(y,y);
}
}
inline void pushup(int p){
tr[p].mn=min(tr[p<<1].mn,tr[p<<1|1].mn);
}
inline void change(int p,int l,int r,int x,int val){
if(l==r){tr[p].mn=val;return;}
int mid=l+r>>1;
if(x<=mid) change(p<<1,l,mid,x,val);
else change(p<<1|1,mid+1,r,x,val);pushup(p);
}
inline int qmn(int p,int l,int r,int x,int y){
if(x<=l&&r<=y) return tr[p].mn;
int mid=l+r>>1,res=inf;
if(x<=mid) res=min(res,qmn(p<<1,l,mid,x,y));
if(y>mid) res=min(res,qmn(p<<1|1,mid+1,r,x,y));
return res;
}
inline int query(int x,int y){
int res=inf;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res=min(res,qmn(1,1,m,pos[top[x]],pos[x]));x=fa[top[x]];
}if(pos[x]>pos[y]) swap(x,y);
res=min(res,qmn(1,1,m,pos[x],pos[y]));
if(x>n) res=min(res,w[fa[x]]);return res;
}
int main(){
// freopen("a.in","r",stdin);
n=read();m=read();Q=read();
for(int i=1;i<=n;++i) w[i]=read();
while(m--){
int x=read(),y=read();
data[++num].to=y;data[num].next=h[x];h[x]=num;
data[++num].to=x;data[num].next=h[y];h[y]=num;
}m=n;tarjan(1,0);dfs1(1);dfnum=0;dfs2(1,1);
for(int i=1;i<=n;++i) change(1,1,m,pos[i],w[i]);
for(int i=1;i+n<=m;++i) change(1,1,m,pos[i+n],W[i].top());
while(Q--){
char op[5];scanf("%s",op+1);int x=read(),y=read();
if(op[1]=='C'){
if(fa[x]){
int z=fa[x];W[z-n].erase(w[x]);
W[z-n].insert(y);change(1,1,m,pos[z],W[z-n].top());
}w[x]=y;change(1,1,m,pos[x],w[x]);continue;
}printf("%d\n",query(x,y));
}return 0;
}