1. 程式人生 > 實用技巧 >題解 P5234 【[JSOI2012]越獄老虎橋】

題解 P5234 【[JSOI2012]越獄老虎橋】

題目連結

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;
}