題解 CF487E 【Tourists】
阿新 • • 發佈:2020-07-25
若從 \(x\) 到 \(y\) 的任意一條路徑經過了一個點雙連通分量,則從 \(x\) 到 \(y\) 一定可以經過該點雙連通分量中的每一個點。
用廣義圓方樹來維護一般無向圖,每個方點的權值為其相鄰的圓點的權值的最小值,然後可以用樹剖來修改和查詢。
但是這樣修改的複雜度是不正確的,若一個圓點相鄰有許多方點,像菊花圖一樣,那麼複雜度是無法接受的。
考慮更改方點的權值定義,權值改為在圓方樹上的其兒子權值的最小值。這樣修改一個圓點時,只用考慮其父親方點的權值的變化,這樣修改複雜度就正確了。
在每個方點上用 \(multiset\) 來維護其兒子的權值,查詢時兩點的 \(lca\) 若為方點,則還要考慮其父親圓點的貢獻。
\(code:\)
#include<bits/stdc++.h> #define maxn 400010 #define maxm 1600010 #define inf 2000000000 #define ls (cur<<1) #define rs (cur<<1|1) #define mid ((l+r)>>1) using namespace std; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } int n,m,q,tot,dfn_cnt,cnt,root=1; int val[maxn],dfn[maxn],low[maxn],st[maxn]; int fa[maxn],de[maxn],siz[maxn],son[maxn],top[maxn],rev[maxn],mi[maxm]; vector<int> ve[maxn]; multiset<int> s[maxn]; char opt[5]; struct edge { int to,nxt; }e[maxn]; int head[maxn],edge_cnt; void add(int from,int to) { e[++edge_cnt]=(edge){to,head[from]}; head[from]=edge_cnt; } void addedge(int x,int y) { ve[x].push_back(y); } void tarjan(int x) { dfn[x]=low[x]=++dfn_cnt,st[++cnt]=x; for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(!dfn[y]) { tarjan(y),low[x]=min(low[x],low[y]); if(dfn[x]<=low[y]) { tot++; int now; do { now=st[cnt--]; addedge(tot,now),addedge(now,tot); }while(now!=y); addedge(tot,x),addedge(x,tot); } } else low[x]=min(low[x],dfn[y]); } } void dfs_son(int x,int fath) { de[x]=de[fath]+1,siz[x]=1,fa[x]=fath,s[fath].insert(val[x]); for(int i=0;i<ve[x].size();++i) { int y=ve[x][i]; if(y==fath) continue; dfs_son(y,x),siz[x]+=siz[y]; if(siz[y]>siz[son[x]]) son[x]=y; } } void dfs_chain(int x,int tp) { dfn[x]=++dfn_cnt,rev[dfn_cnt]=x,top[x]=tp; if(son[x]) dfs_chain(son[x],tp); for(int i=0;i<ve[x].size();++i) { int y=ve[x][i]; if(dfn[y]) continue; dfs_chain(y,y); } } void build(int l,int r,int cur) { if(l==r) { int x=rev[l]; if(x<=n) mi[cur]=val[x]; else mi[cur]=*s[x].begin(); return; } build(l,mid,ls),build(mid+1,r,rs); mi[cur]=min(mi[ls],mi[rs]); } void modify(int l,int r,int pos,int v,int cur) { if(l==r) { mi[cur]=v; return; } if(pos<=mid) modify(l,mid,pos,v,ls); else modify(mid+1,r,pos,v,rs); mi[cur]=min(mi[ls],mi[rs]); } int query(int L,int R,int l,int r,int cur) { if(L<=l&&R>=r) return mi[cur]; int v=inf; if(L<=mid) v=min(v,query(L,R,l,mid,ls)); if(R>mid) v=min(v,query(L,R,mid+1,r,rs)); return v; } int ask(int x,int y) { int v=inf; while(top[x]!=top[y]) { if(de[top[x]]<de[top[y]]) swap(x,y); v=min(v,query(dfn[top[x]],dfn[x],1,tot,root)); x=fa[top[x]]; } if(dfn[x]>dfn[y]) swap(x,y); v=min(v,query(dfn[x],dfn[y],1,tot,root)); if(x>n) v=min(v,val[fa[x]]); return v; } int main() { read(n),read(m),read(q),tot=n,val[0]=inf; for(int i=1;i<=n;++i) read(val[i]); for(int i=1;i<=m;++i) { int x,y; read(x),read(y); add(x,y),add(y,x); } tarjan(1),dfn_cnt=0,memset(dfn,0,sizeof(dfn)); dfs_son(1,0),dfs_chain(1,1),build(1,tot,root); while(q--) { int x,y; scanf("%s",opt),read(x),read(y); if(opt[0]=='C') { s[fa[x]].erase(s[fa[x]].find(val[x])); s[fa[x]].insert(y),val[x]=y; modify(1,tot,dfn[x],y,root); modify(1,tot,dfn[fa[x]],*s[fa[x]].begin(),root); } else printf("%d\n",ask(x,y)); } return 0; }