2018.11.09 codeforces487E. Tourists(tarjan+树链剖分)
程序员文章站
2022-03-03 11:34:18
...
传送门
先把边双连通分量用圆方树一样的方法缩点,然后把新建的树树剖维护。
注意对于边双连通分量需要维护动态最小值,可以用。
代码:
#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=2e5+5,M=3e5+5;
int siz[N],w[N<<1],top[N],dep[N],pred[N],hson[N],num[N],dfn[N],low[N],tot=0,sig=0,n,m,q,blo[N],stk[N],Top=0,fa[N];
struct Node{int l,r,mn;}T[N<<2];
vector<int>g[N],e[N<<1];
multiset<int>W[N<<1];
inline void tarjan(int p,int pre){
dfn[p]=low[p]=++tot,stk[++Top]=p;
for(int i=0;i<g[p].size();++i){
int v=g[p][i];
if(v==pre)continue;
if(!dfn[v]){
tarjan(v,p),low[p]=min(low[p],low[v]);
if(low[v]>=dfn[p]){
int tmp;
++sig,e[p].push_back(sig);
do tmp=stk[Top--],blo[tmp]=sig,e[sig].push_back(tmp),W[sig].insert(w[tmp]);while(tmp^v);
w[sig]=*(W[sig].begin());
}
}
else low[p]=min(low[p],dfn[v]);
}
}
inline void dfs1(int p){
siz[p]=1;
for(int i=0;i<e[p].size();++i){
int v=e[p][i];
if(v==fa[p])continue;
fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];
if(siz[v]>siz[hson[p]])hson[p]=v;
}
}
inline void dfs2(int p,int tp){
top[p]=tp,pred[num[p]=++tot]=p;
if(!hson[p])return;
dfs2(hson[p],tp);
for(int i=0;i<e[p].size();++i){
int v=e[p][i];
if(v!=fa[p]&&v!=hson[p])dfs2(v,v);
}
}
inline void pushup(int p){T[p].mn=min(T[lc].mn,T[rc].mn);}
inline void build(int p,int l,int r){
T[p].l=l,T[p].r=r;
if(l==r){T[p].mn=w[pred[l]];return;}
build(lc,l,mid),build(rc,mid+1,r),pushup(p);
}
inline void update(int p,int k,int v){
if(T[p].l==T[p].r){T[p].mn=v;return;}
if(k<=mid)update(lc,k,v);
else update(rc,k,v);
pushup(p);
}
inline int query(int p,int ql,int qr){
if(ql<=T[p].l&&T[p].r<=qr)return T[p].mn;
if(qr<=mid)return query(lc,ql,qr);
if(ql>mid)return query(rc,ql,qr);
return min(query(lc,ql,mid),query(rc,mid+1,qr));
}
inline int ask(int x,int y){
int ret=1e9;
while(top[x]^top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ret=min(ret,query(1,num[top[x]],num[x])),x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
ret=min(query(1,num[y],num[x]),ret);
if(y>n&&fa[y])ret=min(ret,w[fa[y]]);
return ret;
}
inline void modify(int p,int v){
if(blo[p]){
set<int>::iterator it=W[blo[p]].find(w[p]);
W[blo[p]].erase(it),W[blo[p]].insert(v),w[blo[p]]=*(W[blo[p]].begin()),update(1,num[blo[p]],w[blo[p]]);
}
w[p]=v,update(1,num[p],v);
}
int main(){
sig=n=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(),g[u].push_back(v),g[v].push_back(u);
tarjan(1,0),dfs1(1),tot=0,dfs2(1,1),build(1,1,sig);
for(int i=1,x,y;i<=q;++i){
char s[5];
scanf("%s",s),x=read(),y=read();
if(s[0]=='C')modify(x,y);
else printf("%d\n",ask(x,y));
}
}
上一篇: spring中实例化Bean的三种方式
下一篇: 图的深度优先遍历与广度优先遍历
推荐阅读
-
codeforces CF487E Tourists 边双连通分量 树链剖分
-
CF487E Tourists(圆方树+树链剖分)
-
UOJ#30[Codeforces 487E]Tourists(圆方树+树链剖分)
-
UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树
-
cf487E Tourists 圆方树+树链剖分
-
【CF487E】Tourists-圆方树+multiset+树链剖分
-
2019.04.02【CodeForces487】E. Tourists(圆方树)(树链剖分)(线段树)
-
【CF487E】Tourists【圆方树】【树链剖分】【multiset】
-
【Codeforce 487E】【UOJ#30】—Tourists(圆方树+树链剖分)
-
2018.11.09 codeforces487E. Tourists(tarjan+树链剖分)