RT 我用方点表示整个点双的最小值 并开个 multiset 维护 但是 2 种我认为都对的写法,写法1错,写法2对。
写法一是在找到点双的时候就把全部的 val 插入 multiset
写法二是在树剖 dfs1 时判断父亲是否是方点 是的话就将当前的 val 插入父亲
为什么第一种是错的?这两种的区别应该就是一个点能否对多个 multiset 贡献吧
感谢!
注释有标明
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long
using namespace std;
int rd() {
int f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
ll lrd() {
ll f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
/*
建圆方树 方点的权值是整个双联通的最小值
*/
const int N=(int)(2e5+5),inf=0x3f3f3f3f;
multiset<int>S[N];
int val[N],fa[N],fang_tot;
int dep[N],sz[N],son[N],top[N],id[N],rk[N],sp_tot;
int n,m,Q;
struct edge {
int nex,to;
};
struct GRAPH {
edge e[N<<1]; int head[N],cnt;
GRAPH() {
cnt=0;
}
void add_edge(int x,int y) {
e[++cnt]=(edge){head[x],y}; head[x]=cnt;
}
}G,T;
namespace TAR {
stack<int>ST;
int low[N],dfn[N],tarjan_tot=0;
void tarjan(int x) {
ST.push(x); low[x]=dfn[x]=++tarjan_tot;
for(int i=G.head[x];i;i=G.e[i].nex) {
int y=G.e[i].to;
if(!dfn[y]) {
tarjan(y),low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x]) {
++fang_tot;// S[fang_tot].insert(val[x]); 这里1
int qwq; T.add_edge(fang_tot,x); T.add_edge(x,fang_tot);
do {
qwq=ST.top(); ST.pop(); //S[fang_tot].insert(val[qwq]); 这里1
T.add_edge(fang_tot,qwq); T.add_edge(qwq,fang_tot);
} while(qwq!=y);
}
}
else low[x]=min(low[x],dfn[y]);
}
}
}
struct BIT {
#define ls (cur<<1)
#define rs (ls|1)
int sum[N<<2];
BIT() {
memset(sum,0x3f,sizeof(sum));
}
void update(int cur,int l,int r,int pos,int v) {
if(l==r) return sum[cur]=v,void();
int mid=(l+r)>>1;
if(pos<=mid) update(ls,l,mid,pos,v);
else update(rs,mid+1,r,pos,v);
sum[cur]=min(sum[ls],sum[rs]);
}
int query(int cur,int l,int r,int cl,int cr) {
if(cl<=l&&r<=cr) return sum[cur];
int mid=(l+r)>>1,res=inf;
if(cl<=mid) res=min(res,query(ls,l,mid,cl,cr));
if(cr>mid) res=min(res,query(rs,mid+1,r,cl,cr));
return res;
}
}TR;
void dfs1(int x,int ff) {
fa[x]=ff; sz[x]=1; son[x]=0; dep[x]=dep[ff]+1;
if(x<=n&&ff>n) S[ff].insert(val[x]); //这里2
for(int i=T.head[x];i;i=T.e[i].nex) {
int y=T.e[i].to;
if(y==ff) continue;
dfs1(y,x); sz[x]+=sz[y];
if(sz[y]>sz[son[x]]) son[x]=y;
}
}
void dfs2(int x,int tp) {
top[x]=tp; id[x]=++sp_tot; rk[sp_tot]=x;
if(son[x]) dfs2(son[x],tp);
for(int i=T.head[x];i;i=T.e[i].nex) {
int y=T.e[i].to;
if(y==son[x]||y==fa[x]) continue;
dfs2(y,y);
}
}
void update(int x,int v) {
if(fa[x]) {
S[fa[x]].erase(S[fa[x]].find(val[x])); S[fa[x]].insert(v); TR.update(1,1,fang_tot,id[fa[x]],*S[fa[x]].begin());
}
val[x]=v; TR.update(1,1,fang_tot,id[x],v);
}
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,TR.query(1,1,fang_tot,id[top[x]],id[x]));
x=fa[top[x]];
}
if(id[x]>id[y]) swap(x,y);
res=min(res,TR.query(1,1,fang_tot,id[x],id[y]));
if(x<=n) return res;
else return min(res,val[fa[x]]);
}
int main() {
int x,y; char op; val[0]=inf;
fang_tot=n=rd(); m=rd(); Q=rd();
for(int i=1;i<=n;i++) val[i]=rd();
for(int i=1;i<=m;i++) {
x=rd(); y=rd();
G.add_edge(x,y); G.add_edge(y,x);
}
TAR::tarjan(1); dfs1(1,0); dfs2(1,0);
for(int i=1;i<=n;i++) TR.update(1,1,fang_tot,id[i],val[i]);
for(int i=n+1;i<=fang_tot;i++) TR.update(1,1,fang_tot,id[i],*S[i].begin());
while(Q--) {
cin>>op; x=rd(); y=rd();
if(op=='C') {
update(x,y);
} else printf("%d\n",query(x,y));
}
return 0;
}