码迷,mamicode.com
首页 > Web开发 > 详细

题解 P5234 【[JSOI2012]越狱老虎桥】

时间:2020-11-11 16:51:13      阅读:77      评论:0      收藏:0      [点我收藏+]

标签:ref   min   include   begin   getch   lang   最大值   false   put   

题目链接

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

题解 P5234 【[JSOI2012]越狱老虎桥】

标签:ref   min   include   begin   getch   lang   最大值   false   put   

原文地址:https://www.cnblogs.com/colazcy/p/13768489.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!