題解 P5234 【[JSOI2012]越獄老虎橋】
阿新 • • 發佈:2020-10-04
Solution [JSOI2012]越獄老虎橋
題目大意:給定一張帶權無向圖,你可以任意新增一條邊,求權值最小的割邊的最大值
Tarjan,貪心
分析:
我們先考慮是一棵樹的情況,顯然每一條邊都是割邊,我們新增一條邊可以產生一個簡單環,那麼環上的所有邊就都不是割邊了
考慮貪心,我們將邊權從小到大排序,逐次加入,如果當前邊無法和之前的所有邊構成一條鏈,那麼當前邊權就是答案(也就是貪心的儘量將最小的幾條割邊丟進一個環裡面)
對於普通無向圖,縮點之後用同樣的方法處理
如何判斷能否構成一條鏈,可以記錄一下鏈的起點終點,結合父子關係 / \(\text{LCA}\)討論一下即可,詳見程式碼
#include <cstdio> #include <cctype> #include <algorithm> #include <vector> #include <queue> using namespace std; const int maxn = 5e5 + 100; inline int read(){ int x = 0;char c = getchar(); while(!isdigit(c))c = getchar(); while(isdigit(c))x = x * 10 + c - '0',c = getchar(); return x; } struct edge{ int u,v,d; bool operator < (const edge &rhs)const{ return d < rhs.d; } }edges[maxn << 1]; int head[maxn],nxt[maxn << 1],tot = 1; inline void addedge(int u,int v,int d){ edges[++tot] = edge{u,v,d}; nxt[tot] = head[u]; head[u] = tot; } int dfn[maxn],low[maxn],iscut[maxn << 1],dfs_tot; void tarjan(int u,int faz){ dfn[u] = low[u] = ++dfs_tot; for(int i = head[u];i;i = nxt[i]){ int v = edges[i].v; if(!dfn[v]){ tarjan(v,i); low[u] = min(low[u],low[v]); if(low[v] > dfn[u])iscut[i] = iscut[i ^ 1] = 1; }else if((i ^ 1) != faz)low[u] = min(low[u],dfn[v]); } } int col[maxn],col_tot; inline void bfs(int s,int c){ queue<int> q; q.push(s); while(!q.empty()){ int u = q.front();q.pop(); col[u] = c; for(int i = head[u];i;i = nxt[i]){ int v = edges[i].v; if(iscut[i] || col[v])continue; q.push(v); } } } vector<int> G[maxn]; vector<edge> vec; inline void addedge(int u,int v){G[u].push_back(v);} const int maxdep = 26; int dep[maxn],faz[maxn][maxdep + 1],rt,fir,lst; inline void dfs(int u){ for(int i = 1;i <= maxdep;i++)faz[u][i] = faz[faz[u][i - 1]][i - 1]; for(int v : G[u]){ if(v == faz[u][0])continue; dep[v] = dep[u] + 1; faz[v][0] = u; dfs(v); } } inline int isson(int x,int y){ if(x == y)return false; for(int i = maxdep;i >= 0;i--) if(dep[faz[x][i]] >= dep[y])x = faz[x][i]; return x == y; } inline int lca(int x,int y){ if(dep[x] < dep[y])swap(x,y); for(int i = maxdep;i >= 0;i--) if(dep[faz[x][i]] >= dep[y])x = faz[x][i]; if(x == y)return x; for(int i = maxdep;i >= 0;i--) if(faz[x][i] != faz[y][i])x = faz[x][i],y = faz[y][i]; return faz[x][0]; } int n,m; int main(){ n = read(),m = read(); for(int u,v,d,i = 1;i <= m;i++){ u = read(),v = read(),d = read(); addedge(u,v,d); addedge(v,u,d); } for(int i = 1;i <= n;i++) if(!dfn[i])tarjan(i,0); for(int i = 1;i <= n;i++) if(!col[i])bfs(i,++col_tot); for(int i = 2;i <= tot;i++){ int u = edges[i].u,v = edges[i].v; if(col[u] != col[v])addedge(col[u],col[v]); if(iscut[i] && (i & 1))vec.push_back(edge{col[u],col[v],edges[i].d}); } sort(vec.begin(),vec.end()); if(vec.empty())return puts("-1"),0; rt = vec[0].u; dep[rt] = 1; dfs(rt); for(auto &e : vec) if(dep[e.u] > dep[e.v])swap(e.u,e.v); for(auto e : vec){ if(!fir){ fir = e.u; lst = e.v; continue; } if((isson(e.u,fir) || e.u == fir) && !isson(lca(lst,e.u),fir))fir = e.v; else if((isson(e.u,lst) || e.u == lst) && !isson(lca(fir,e.u),lst))lst = e.v; else return printf("%d\n",e.d),0; } return 0; }