[BZOJ4331] [JSOI2012]越獄老虎橋
阿新 • • 發佈:2020-09-06
[BZOJ4331] [JSOI2012]越獄老虎橋
首先根據題目的意思,這個無向圖中 每一個邊雙聯通分量 的點都是等價的
據此,建出一棵邊雙生成樹,樹邊即為原圖的割邊,樹邊帶權
考慮最優的情況實際上是連線了兩個葉子\((u,v)\),把圖展開後,就會發現,就是把\(u,v\)到根路徑上所有的點都縮進了同一個環
由於這個環是與1相連的,所以斷掉環上的邊顯然不合法,而不在環上的邊,只需要隨便斷掉一條,就能讓一個點不連通
也就是說,答案是 (去掉兩條\((1,u)\)鏈上的所有邊,剩下的邊中最小值) 的最大值
設答案為\(ans\)
考慮這個問題實際上等價於所有的\(e\in E,w(e)\leq ans\)
形象化的描述就是: 這些邊至少分成了 三條岔開的鏈
做法1:
考慮二分答案,把每條\(e\in E,w(e)\leq ans\)的邊的下端點加入,判斷這樣生成的聯通塊是否含有3個葉子即可
複雜度為\(O(n\log n)\)
做法2:
樹形\(\text{dp}\)求解,實際上這個問題就是 (選擇了合法的3條邊中邊權的最大值) 的最小值
考慮類似揹包的做法,每次合併可以加入\((u,v,w)\)這條邊,或者從兒子合併揹包陣列
揹包大小是3,因此複雜度為\(O(n)\)
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define reg register #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i) #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i) template <class T> inline void cmin(T &a,const T &b){ ((a>b)&&(a=b)); } char IO; template <class T=int> T rd(){ T s=0; int f=0; while(!isdigit(IO=getchar())) if(IO=='-') f=1; do s=(s<<1)+(s<<3)+(IO^'0'); while(isdigit(IO=getchar())); return f?-s:s; } const int N=5e5+10,INF=1e9+10; int n,m; struct Edge{ int to,nxt,w; } e[N*6]; int head[N],ecnt; void AddEdge(int u,int v,int w) { e[++ecnt]=(Edge){v,head[u],w}; head[u]=ecnt; } #define erep(u,i) for(int i=head[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to) int low[N],t[N],id[N],scc,dfn; int stk[N],top; void dfs(int u,int f) { low[u]=t[u]=++dfn; stk[++top]=u; erep(u,i) if(v!=f) { if(!t[v]) dfs(v,u),cmin(low[u],low[v]); else cmin(low[u],t[v]); } if(low[u]==t[u]){ int v; ++scc; do v=stk[top--],id[v]=scc; while(v!=u); } } int head2[N]; void AddEdge2(int u,int v,int w) { e[++ecnt]=(Edge){v,head2[u],w}; head2[u]=ecnt; } #define erep2(u,i) for(int i=head2[u],v=e[i].to,w=e[i].w;i;i=e[i].nxt,v=e[i].to,w=e[i].w) int ans=INF; int dp[N][4],tmp[4]; // 樹形dp void dfs1(int u,int f) { dp[u][0]=0,dp[u][1]=dp[u][2]=dp[u][3]=INF; erep2(u,i) if(v!=f) { dfs1(v,u); memset(tmp,63,sizeof tmp); rep(j,0,3) { cmin(tmp[j],dp[u][j]); if(j<3) cmin(tmp[j+1],max(dp[u][j],w)); rep(k,0,3-j) cmin(tmp[j+k],max(dp[u][j],dp[v][k])); } rep(j,0,3) dp[u][j]=tmp[j]; } cmin(ans,dp[u][3]); } int MT; int main(){ n=rd(),m=rd(); rep(i,1,m) { int u=rd(),v=rd(),w=rd(); AddEdge(u,v,w),AddEdge(v,u,w); cmax(MT,w); } dfs(1,0); rep(u,1,n) erep(u,i) if(id[u]!=id[v]) AddEdge2(id[u],id[v],e[i].w); // 構建生成樹 dfs1(id[1],0); printf("%d\n",ans==INF?-1:ans); }