Tourists——圓方樹
阿新 • • 發佈:2018-11-30
一般圖,帶修求所有簡單路徑代價。
簡單路徑,不能經過同一個點兩次,那麼每個V-DCC出去就不能再回來了。
所以可以圓方樹,然後方點維護一下V-DCC內的最小值。
那麼,從任意一個割點進入這個DCC,必然可以繞一圈再從另一個割點出去。
所以,路徑上的最小值,就是圓方樹路徑上的最小值。方點的最小值就是在這個DCC中走一走得到的。
樹鏈剖分+線段樹維護路徑
用堆維護方點四周的圓點的最小值。然後更新。
一個問題是:
更新一個割點圓點,會影響到四周所有的方點。暴力更新,菊花圖直接TLE
這樣更新:
方點只維護圓方樹上兒子圓點的最值。
這樣,每次修改圓點,只要修改father的方點的值即可。
查詢路徑的時候,如果LCA是方點,那麼把這個方點的father的值也取min即可。
圓點就無所謂了。LCA自己一定會取到的。
程式碼:
#include<bits/stdc++.h> #define reg register int #define mid ((l+r)>>1) #define il inline #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=2e5+5; const int inf=0x3f3f3f3f; int n,m,q; struct node{ int nxt,to; }e[2*N],bian[2*N]; int hd[N],pre[N];int cnt1,cnt2; void _add(int x,int y){ bian[++cnt1].nxt=pre[x]; bian[cnt1].to=y; pre[x]=cnt1; } void add(int x,int y){ e[++cnt2].nxt=hd[x]; e[cnt2].to=y; hd[x]=cnt2; } struct heap{ priority_queue<int,vector<int>,greater<int> >h,d; int top(){ while(h.size()&&d.size()&&h.top()==d.top()){ h.pop();d.pop(); } if(h.empty()) return inf; return h.top(); } void push(int c){ h.push(c); } void dele(int c){ d.push(c); } }f[N]; int w[N]; int tot,df; int dfn[N],low[N],sta[N],tp; void tarjan(int x){ dfn[x]=low[x]=++df; sta[++tp]=x; for(reg i=pre[x];i;i=bian[i].nxt){ int y=bian[i].to; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); if(dfn[x]<=low[y]){ ++tot;//fang w[tot]=inf;//warning!!! int z; do{ z=sta[tp--]; add(tot,z);add(z,tot); }while(z!=y); add(x,tot);add(tot,x); } } else low[x]=min(low[x],dfn[y]); } } int dep[N],fa[N],top[N],fdfn[N],son[N],sz[N]; void dfs1(int x,int d){ dep[x]=d; sz[x]=1; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(y==fa[x]) continue; fa[y]=x; dfs1(y,d+1); sz[x]+=sz[y]; if(sz[y]>sz[son[x]]) son[x]=y; if(x>n){//a fang f[x].push(w[y]); w[x]=min(w[x],w[y]); } } } void dfs2(int x){ dfn[x]=++df; fdfn[df]=x; if(!top[x]) top[x]=x; if(son[x]) top[son[x]]=top[x],dfs2(son[x]); for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(y==fa[x]) continue; if(y==son[x]) continue; dfs2(y); } } int mi[4*N]; void pushup(int x){ mi[x]=min(mi[x<<1],mi[x<<1|1]); } void build(int x,int l,int r){ if(l==r){ mi[x]=w[fdfn[l]];return; } build(x<<1,l,mid); build(x<<1|1,mid+1,r); pushup(x); } void chan(int x,int l,int r,int to,int c){ if(l==r){ mi[x]=c;return; } if(to<=mid) chan(x<<1,l,mid,to,c); else chan(x<<1|1,mid+1,r,to,c); pushup(x); } int query(int x,int l,int r,int L,int R){ if(L<=l&&r<=R){ return mi[x]; } int ret=inf; if(L<=mid) ret=min(ret,query(x<<1,l,mid,L,R)); if(mid<R) ret=min(ret,query(x<<1|1,mid+1,r,L,R)); return ret; } int wrk(int x,int y){ int ret=inf; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); ret=min(ret,query(1,1,tot,dfn[top[x]],dfn[x])); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); ret=min(ret,query(1,1,tot,dfn[y],dfn[x])); if(y>n) ret=min(ret,w[fa[y]]); return ret; } int main(){ rd(n);rd(m);rd(q); for(reg i=1;i<=n;++i)rd(w[i]); int x,y; for(reg i=1;i<=m;++i){ rd(x);rd(y); _add(x,y);_add(y,x); } tot=n; tarjan(1); memset(dfn,0,sizeof dfn); df=0; dfs1(1,1); dfs2(1); build(1,1,tot); char ch[10]; while(q--){ scanf("%s",ch+1); if(ch[1]=='A'){ rd(x);rd(y); printf("%d\n",wrk(x,y)); } else{ rd(x);rd(y); int ff=fa[x]; f[ff].dele(w[x]); f[ff].push(y); int tmp=f[ff].top(); chan(1,1,tot,dfn[ff],tmp); w[ff]=tmp;//no use in fact w[x]=y; chan(1,1,tot,dfn[x],y); } } return 0; } } int main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2018/11/30 16:10:40 */