[CodeForces 487E]Tourists
Description
\(n\)个点,\(m\)条边的无向连通图,每个点有点权。
有两种操作:
- 修改某个点的点权。
- 询问两点间所有简单路径上点权最小值。
Solution
建出圆方树。令方点点权为相邻圆点点权的最小值。那么现在询问就变成查询路径最小值,可以用树剖+线段树解决。
对于修改,如果修改某个点权值,那么它周围的所有方点权值都要修改,可以被卡成\(\text O(n)\)。
所以改一下思路,考虑到圆方树是一棵树,可以令方点点权为其儿子圆点点权的最小值。这样,修改一个圆点,只需要顺带修改其父亲方点的点权即可。
对于每方点,用一个multiset维护所有儿子圆点的权值。
值得注意的是,如果查询时两点lca是方点,那还要查询其父亲圆点的权值。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read(){//be careful for long long!
register int x=0,f=1;register char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
return f?x:-x;
}
const int N=1e5+10;
int n,m,q,w[N<<1],cnt,dfc,dfn[N<<1],low[N],stk[N],tp;
vector<int> re_E[N],E[N<<1];
#define pb(x) push_back(x)
inline void Tarjan(int nw){
dfn[nw]=low[nw]=++dfc;stk[++tp]=nw;
for(int to:re_E[nw])
if(!dfn[to]){
Tarjan(to);
low[nw]=min(low[nw],low[to]);
if(low[to]==dfn[nw]){
++cnt;
for(int x=0;x^to;--tp){
x=stk[tp];
E[x].pb(cnt),E[cnt].pb(x);
}
E[nw].pb(cnt),E[cnt].pb(nw);
}
}
else low[nw]=min(low[nw],dfn[to]);
}
namespace TCP{
const int _=2e5+10;
int son[_],siz[_],fa[_],dep[_],tp[_],rol[_];
multiset<int> W[_>>1];
struct Segment_tree{
#define ls(p) p<<1
#define rs(p) p<<1|1
int tr[_<<2];
inline void update(int p){tr[p]=min(tr[ls(p)],tr[rs(p)]);return;}
inline void Build(int p,int l,int r){
if(l==r){tr[p]=w[rol[l]];return;}
int mid=(l+r)>>1;
Build(ls(p),l,mid),Build(rs(p),mid+1,r);
update(p);
}
inline void Modify(int p,int l,int r,int pos,int val){
if(l==r){tr[p]=val;return;}
int mid=(l+r)>>1;
if(mid>=pos)Modify(ls(p),l,mid,pos,val);
else Modify(rs(p),mid+1,r,pos,val);
update(p);
}
inline int Query(int p,int l,int r,int L,int R){
if(L<=l&&r<=R)return tr[p];
int mid=(l+r)>>1,ans=2e9;
if(mid>=L)ans=min(ans,Query(ls(p),l,mid,L,R));
if(mid<R)ans=min(ans,Query(rs(p),mid+1,r,L,R));
return ans;
}
}T;
inline void Dfs_o(int nw,int f=0){
siz[nw]=1;dep[nw]=dep[fa[nw]]+1;
for(int to:E[nw])
if(to^f){
fa[to]=nw;Dfs_o(to,nw);siz[nw]+=siz[to];
if(siz[to]>siz[son[nw]])son[nw]=to;
if(nw>n)W[nw-n].insert(w[to]);
}
}
inline void Dfs_t(int nw){
dfn[nw]=++dfc;rol[dfc]=nw;
if(!tp[nw])tp[nw]=nw;
if(son[nw]){tp[son[nw]]=tp[nw];Dfs_t(son[nw]);}
for(int to:E[nw])
if(to^fa[nw]&&to^son[nw])
Dfs_t(to);
}
inline int lca(int x,int y){
int ans=0x7fffffff;
while(tp[x]^tp[y]){
if(dep[tp[x]]>=dep[tp[y]])ans=min(ans,T.Query(1,1,dfc,dfn[tp[x]],dfn[x])),x=fa[tp[x]];
else ans=min(ans,T.Query(1,1,dfc,dfn[tp[y]],dfn[y])),y=fa[tp[y]];
}
if(dep[x]>dep[y])swap(x,y);
ans=min(ans,T.Query(1,1,dfc,dfn[x],dfn[y]));
if(x>n)ans=min(ans,w[fa[x]]);
return ans;
}
}using namespace TCP;
int main(){
n=cnt=read(),m=read(),q=read();
for(int i=1;i<=n;++i)w[i]=read();
for(int i=1,u,v;i<=m;++i)u=read(),v=read(),re_E[u].pb(v),re_E[v].pb(u);
Tarjan(1);memset(dfn,0,sizeof(dfn));dfc=0;
Dfs_o(1),Dfs_t(1);
for(int i=n+1;i<=dfc;++i)w[i]=(*W[i-n].begin());
T.Build(1,1,dfc);
while(q--){
char ch=getchar();
switch(ch){
case 'C':{
int x=read();
if(x^1){
W[fa[x]-n].erase(W[fa[x]-n].find(w[x]));
W[fa[x]-n].insert(w[x]=read());
T.Modify(1,1,dfc,dfn[fa[x]],(*W[fa[x]-n].begin()));
}
else w[x]=read();
T.Modify(1,1,dfc,dfn[x],w[x]);
break;
}
case 'A':{
int x=read(),y=read();
printf("%d\n",TCP::lca(x,y));
break;
}
}
}
return 0;
}