【Codeforces Round 364 (Div 2)F】【暴力 双连通分量求桥】Break Up n点m边最多割2边最小成本使得S与T不联通

F. Break Up
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Again, there are hard times in Berland! Many towns have such tensions that even civil war is possible.

There are n towns in Reberland, some pairs of which connected by two-way roads. It is not guaranteed that it is possible to reach one town from any other town using these roads.

Towns s and t announce the final break of any relationship and intend to rule out the possibility of moving between them by the roads. Now possibly it is needed to close several roads so that moving from s to t using roads becomes impossible. Each town agrees to spend money on closing no more than one road, therefore, the total number of closed roads will be no more than two.

Help them find set of no more than two roads such that there will be no way between s and t after closing these roads. For each road the budget required for its closure was estimated. Among all sets find such that the total budget for the closure of a set of roads is minimum.

Input

The first line of the input contains two integers n and m (2 ≤ n ≤ 10000 ≤ m ≤ 30 000) — the number of towns in Berland and the number of roads.

The second line contains integers s and t (1 ≤ s, t ≤ ns ≠ t) — indices of towns which break up the relationships.

Then follow m lines, each of them contains three integers xiyi and wi (1 ≤ xi, yi ≤ n1 ≤ wi ≤ 109) — indices of towns connected by the i-th road, and the budget on its closure.

All roads are bidirectional. It is allowed that the pair of towns is connected by more than one road. Roads that connect the city to itself are allowed.

Output

In the first line print the minimum budget required to break up the relations between s and t, if it is allowed to close no more than two roads.

In the second line print the value c (0 ≤ c ≤ 2) — the number of roads to be closed in the found solution.

In the third line print in any order c diverse integers from 1 to m — indices of closed roads. Consider that the roads are numbered from1 to m in the order they appear in the input.

If it is impossible to make towns s and t disconnected by removing no more than 2 roads, the output should contain a single line -1.

If there are several possible answers, you may print any of them.

Examples
input
6 7
1 6
2 1 6
2 3 5
3 4 9
4 6 4
4 6 5
4 5 1
3 1 3
output
8
2
2 7
input
6 7
1 6
2 3 1
1 2 2
1 3 3
4 5 4
3 6 5
4 6 6
1 5 7
output
9
2
4 5
input
5 4
1 5
2 1 3
3 2 1
3 4 4
4 5 2
output
1
1
2
input
2 3
1 2
1 2 734458840
1 2 817380027
1 2 304764803
output
-1
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 1010, M = 6e5 + 10, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int n, m;
int ST, ED;
bool vis[N];
pair<int,int> pre[N];
int first[N], id;
int w[M], c[M], nxt[M];
bool use[M >> 1];
void ins(int x, int y, int z)
{
	w[++id] = y;
	c[id] = z;
	nxt[id] = first[x];
	first[x] = id;
}
void dfs(int x)
{
	vis[x] = 1;
	for (int z = first[x]; z; z = nxt[z])
	{
		int y = w[z];
		if (vis[y])continue;
		pre[y] = MP(x, z); dfs(y);
	}
}
int dfn[N], low[N], tim;
int sta[N], top; bool insta[N];
int ans1, ans2;
int ans;
vector<int>ANS;
void update()
{
	if (c[ans1 << 1] + c[ans2 << 1] < ans)
	{
		ans = c[ans1 << 1] + c[ans2 << 1];
		ANS.clear();
		ANS.push_back(ans1);
		if (ans2)ANS.push_back(ans2);
	}
}
void tarjan(int x, int lastz)
{
	dfn[x] = low[x] = ++tim;
	sta[++top] = x; insta[x] = 1;
	for (int z = first[x]; z; z = nxt[z])if (use[z >> 1])
	{
		if ((z^lastz) == 1)continue;
		int y = w[z];
		if (dfn[y] == 0)tarjan(y, z);
		if (insta[y])gmin(low[x], low[y]);
		if (low[y] > dfn[x])
		{
			if (dfn[ED] >= dfn[y])
			{
				ans2 = z >> 1;
				update();
			}
		}
	}
	if (dfn[x] == low[x])
	{
		while (1)
		{
			int y = sta[top--]; insta[y] = 0;
			if (y == x)break;
		}
	}
}
void del(int x)
{
	if (x == ST)return;
	del(pre[x].first);
	int z = pre[x].second >> 1;
	ans1 = z;
	ans2 = 0;
	use[z] = 0;
	tim = 0; 
	for (int i = 1; i <= n; ++i)dfn[i] = 0;
	tarjan(ST, 0);
	if (!dfn[ED])update();
	use[z] = 1;
}
int main()
{
	while(~scanf("%d%d",&n, &m))
	{
		for (int i = 1; i <= n; ++i)
		{
			first[i] = 0;
			vis[i] = 0;
		}
		id = 1;
		scanf("%d%d", &ST, &ED);
		for (int i = 1; i <= m; ++i)
		{
			int x, y, z;
			scanf("%d%d%d", &x, &y, &z);
			ins(x, y, z);
			ins(y, x, z);
			use[i] = 1;
		}
		dfs(ST);
		if (!vis[ED])
		{
			puts("0");
			puts("0");
			puts("");
			continue;
		}
		ans = 2.1e9;
		del(ED);
		if (ans == 2.1e9)puts("-1");
		else
		{
			printf("%d\n", ans);
			printf("%d\n", ANS.size());
			for (int i = 0; i < ANS.size(); ++i)printf("%d ", ANS[i]); puts("");
		}
	}
	return 0;
}
/*
【trick&&吐槽】
复杂度分析很重要。
当我们知道O(nm)的复杂度可行的时候,为什么不想想暴力的算法呢?

【题意】
给你一个图,图上n(1000)点m(30000)边
我们最多可以在这个图上删掉2条边。
问你是否可以在删除<=2条边的条件下,使得从s到t不连通。
如果可以,输出最小删除成本。

【类型】
最短路 双连通分量

【分析】
首先,我们很容易搜出一条从s到t的路径(每个点最多只经过一次)
如果搜不出这样的路径,答案肯定为0 0

如果搜的出,这条路径上显然至少要删除一条边(否则这个路径完好,ST与ED会保持联通)。
我们枚举删的是哪条边,然后在之后的图上求是否存在ST与ED的桥边,同时还求出是否能从ST搜到ED。

1,如果干脆无法从ST搜到ED,那么显然答案可以被我们之前枚举删掉的第一条边更新
2,如果可以从ST搜到ED。
	(1)如果不存在ST到ED的桥边,那么答案可以被删掉的第一条边+该桥边更新
	(2)如果存在ST到ED的桥边,那么答案无法更新。

最后输出答案即可(注意答案要初始化为极大值,判定无解情况)
过程中,最大的难点,在于如何判定哪些边是ST到ED的桥边。

判定桥边这样的有关连通性的程序,我们往往可以由tarjan算法实现。
那我们怎么写这个tarjan呢?
当然包括了——
1,入栈时间戳dfn[]
2,双联通块内最小时间戳low[]
3,栈sta[]
4,入栈标记insta[]

然后我们不走删掉的边,同时也不走反父边
然后——
如果子节点未走过,则扩展子联通块y。
如果子联通块与其祖先有连接,则low[y]!=dfn[y],且y会留在栈中,我们边会相应更新low[x]
否则y会退栈,我们无法更新low[x]
如果low[y] > dfn[x],说明这条边,对于y而言,是桥。

我们找到桥了,那ED是否与y一起在桥另外一侧的联通块内呢?
这里有一个很精妙的判定条件——
(dfn[ED]>=dfn[y])
这个条件意味着什么呢?

意味着ED是在y之后扩展出来的。
也就是说——
ED是y的子孙。

因为我们形成的dfn[]扩展,是以一棵搜索树的形式展开。
我们当前x与y形成了割边关系,
如果ED不在y所在的子树内,
要不ED的搜索先于y,那么dfn[ED]<dfn[y]
要不ED的搜索不先于y,那么dfn[ED]==0 或 dfn[ED]>=y且ED为y的子孙。
于是这种写法可以支持我们AC哦~

【时间复杂度&&优化】
O(nm)

*/



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值