##Description Cyberland 有 n 座城市,編號從 1 到 n,有 m 條雙向道路鏈接這些城市。第 j 條路鏈接城市 aj 和 bj。天天,都有成千上萬的遊客來到 Cyberland 遊玩。 在每個城市,都有記念品售賣,第 i 個城市售價爲 wi。這個售價有時會變更。 每個遊客的遊覽路徑都有固定起始城市和終止城市,且不會通過重複的城市。 他們會在路徑上的城市中,售價最低的那個城市購買記念品。 你能求出每個遊客在全部合法的路徑中能購買的最低售價是多少嗎? 你要處理 q個操做: C a w: 表示 a 城市的記念品售價變成 w。 A a b: 表示有一個遊客要從 a 城市到 b 城市,你要回答在全部他的旅行路徑中最低售價的最低可能值。c++
##Solution $tarjan$求出雙連通份量,創建圓方樹,而後答案就是圓方樹上兩點間的通過的點的最小值,樹鏈剖分維護便可 方點原本是全部相鄰圓點的權值最小值,此題中帶修改,考慮維護一個父子關係,每次修改就只須要改父親的方點便可 注意樹鏈剖分查詢時,若是鏈頂是方點,還須要查詢其父親的方點的權值,由於這個方點也屬於這個雙連通份量 方點的權值改用堆維護便可ui
#include <bits/stdc++.h> #define ls (o<<1) #define rs (o<<1|1) using namespace std; const int N=2e5+10,inf=1e9+10; int n,m,Q,a[N],head[N],nxt[N<<2],to[N<<2],num=0,st[N],cnt=0,dep[N],Head[N]; int low[N],dfn[N],DFN=0,W,sz[N],son[N],fa[N],top[N],tr[N<<2],id[N],b[N]; struct H{ priority_queue<int>d,s; inline void upd(){ while(!s.empty() && !d.empty() && s.top()==d.top())s.pop(),d.pop(); } inline void push(int x){s.push(-x);} inline void del(int x){d.push(-x);} inline int top(){upd();return -s.top();} }q[N]; inline void link(int x,int y){ nxt[++num]=head[x];to[num]=y;head[x]=num; nxt[++num]=head[y];to[num]=x;head[y]=num; } inline void link2(int x,int y){ nxt[++num]=Head[x];to[num]=y;Head[x]=num; nxt[++num]=Head[y];to[num]=x;Head[y]=num; } inline void tarjan(int x,int last){ low[x]=dfn[x]=++DFN;st[++cnt]=x; for(int i=head[x];i;i=nxt[i]){ int u=to[i];if(u==last)continue; if(!dfn[u]){ tarjan(u,x); low[x]=min(low[x],low[u]); if(low[u]>=dfn[x]){ link2(++n,x);a[n]=inf; while(st[cnt]!=u)link2(n,st[cnt--]); link2(n,st[cnt--]); } } else low[x]=min(low[x],dfn[u]); } } inline void dfs1(int x){ sz[x]=1; for(int i=Head[x];i;i=nxt[i]){ int u=to[i]; if(sz[u])continue; if(x>W)q[x].push(a[u]); dep[u]=dep[x]+1;fa[u]=x;dfs1(u);sz[x]+=sz[u]; if(sz[u]>sz[son[x]])son[x]=u; } } inline void dfs2(int x,int tp){ top[x]=tp;id[x]=++DFN;b[DFN]=x; if(son[x])dfs2(son[x],tp); for(int i=Head[x];i;i=nxt[i]) if(to[i]!=son[x] && to[i]!=fa[x])dfs2(to[i],to[i]); } inline void build(int l,int r,int o){ if(l==r){tr[o]=a[b[l]];return ;} int mid=(l+r)>>1; build(l,mid,ls);build(mid+1,r,rs); tr[o]=min(tr[ls],tr[rs]); } inline void Modify(int l,int r,int o,int sa,int t){ if(l==r){tr[o]=t;return ;} int mid=(l+r)>>1; if(sa<=mid)Modify(l,mid,ls,sa,t); else Modify(mid+1,r,rs,sa,t); tr[o]=min(tr[ls],tr[rs]); } inline void updata(int x,int y){ if(fa[x]){ q[fa[x]].del(a[x]);q[fa[x]].push(y); Modify(1,n,1,id[fa[x]],a[fa[x]]=q[fa[x]].top()); } a[x]=y;Modify(1,n,1,id[x],y); } inline int qry(int l,int r,int o,int sa,int se){ if(sa<=l && r<=se)return tr[o]; int mid=(l+r)>>1; if(se<=mid)return qry(l,mid,ls,sa,se); else if(sa>mid)return qry(mid+1,r,rs,sa,se); else return min(qry(l,mid,ls,sa,mid),qry(mid+1,r,rs,mid+1,se)); } inline int query(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,qry(1,n,1,id[top[x]],id[x])); x=fa[top[x]]; } if(id[x]>id[y])swap(x,y); ret=min(ret,qry(1,n,1,id[x],id[y])); if(x>W)ret=min(ret,a[fa[x]]); return ret; } int main() { freopen("pp.in","r",stdin); freopen("pp.out","w",stdout); scanf("%d%d%d",&n,&m,&Q); int x,y;char S[3];W=n; for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); link(x,y); } tarjan(1,1); DFN=0;dfs1(1);dfs2(1,1); for(int i=W+1;i<=n;i++)a[i]=q[i].top(); build(1,n,1); while(Q--){ scanf("%s%d%d",S,&x,&y); if(S[0]=='C')updata(x,y); else printf("%d\n",query(x,y)); } return 0; }