codeforces 723F 并查集+贪心

先去掉\(s\)\(t\)做一个最小生成森林并缩点,然后把缩后的点分成三类:
  - I. 不与\(s\)\(t\)中任意一个点相连。若存在这类点则无解;
  - II. 仅与\(s\)\(t\)中的一个点相连。肯定要连上。
  - III. 与\(s\)\(t\)都相连。在II型点都处理完后再处理III型点。贪心一下,每次取\(s\)\(t\)中所剩的度数较多那一个连之即可;如果到过程中发现度数不够,则无解。
  但要注意一个细节!如果\(s\)\(t\)在原图中就是相连的,必须连这条边的充要条件是:所有缩后的点都是II型点。因为我们要保证\(s\)\(t\)相连,所以有两种选择:一是把一个III型点的两条边都连上(如果有III型点);二是连\(s\)\(t\)的边(如果有)。显然,如果存在III型点,还连s-t边的方案不会更优。所以,只有当迫不得已(全都是II型点)的时候,才连s-t边救场子。反过来,如果全是II型点却没有s-t边,是无解的。
  用一堆数组记录方案。
  代码如下:

#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;

 #define rep(i,a,b) for (int i = a; i <= b; i++) 
 #define dep(i,a,b) for (int i = a; i >= b; i--)
 #define vep(i,v) for (int i = 0; i < (int)v.size(); i++)
 #define read(x) scanf("%d", &x)
 #define fill(a,x) memset(a, x, sizeof(a))
 #define mp make_pair
 #define pb push_back

 const int N = 200000 + 5, M = 400000 + 5;

 int n, m, u[M], v[M], s, t, ds, dt, cnt = 0, id[N], from[N][2], fa[N];
 bool con[N][2], link[N][2], need_direct = true;
 vector<pair<int, int> > ans;

 int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

 void init() {
 	fill(con, false);
 	fill(link, false);
 	fill(id, 0);
 }

 bool is_st(int x) { return (x == s || x == t); }

int main()
{
	read(n); read(m);
	rep(i,1,m) read(u[i]), read(v[i]);
	read(s); read(t); read(ds); read(dt);

	init();
	rep(i,1,m) {
		if (u[i] == s) con[v[i]][0] = true;
		if (u[i] == t) con[v[i]][1] = true;
		if (v[i] == s) con[u[i]][0] = true;
		if (v[i] == t) con[u[i]][1] = true;
	}

    rep(i,1,n) fa[i] = i;
	rep(i,1,m) {
		int x = u[i], y = v[i];
		if (is_st(x) || is_st(y)) continue;
		int f1 = find(x), f2 = find(y);
		if (f1 != f2) { fa[f1] = f2; ans.pb(mp(x, y)); }
	}

	rep(i,1,n) {
		if (is_st(i)) continue;
		int f = find(i);
		if (!id[f]) { cnt++; id[f] = cnt; }
		int j = id[f];
		if (con[i][0]) { link[j][0] = true; from[j][0] = i; }
		if (con[i][1]) { link[j][1] = true; from[j][1] = i; }
	}

	rep(i,1,cnt) 
		if (link[i][0] ^ link[i][1]) {
			if (link[i][0]) { ds--; ans.pb(mp(from[i][0], s)); }
			if (link[i][1]) { dt--; ans.pb(mp(from[i][1], t)); }
		}
		else {
			need_direct = false;
			if ((link[i][0] | link[i][1]) == 0) { printf("No\n"); return 0; }
		}

    bool st_have_linked = false;
	if (need_direct) {
		rep(i,1,m) 
			if (is_st(u[i]) && is_st(v[i])) { 
				dt--; ds--;
				ans.pb(mp(t, s));
				need_direct = false;
				break;
			}
			if (need_direct) { printf("No\n"); return 0; }
	}
	else 
		rep(i,1,cnt) if (link[i][0] & link[i][1]) {
			if (!st_have_linked) { 
				ds--; ans.pb(mp(from[i][0], s)); 
				dt--; ans.pb(mp(from[i][1], t));
				st_have_linked = true;
				continue;
			}
			if (ds >= dt) 
				{ ds--; ans.pb(mp(from[i][0], s)); }
			else
				{ dt--; ans.pb(mp(from[i][1], t)); }
			if (ds < 0 || dt < 0) { printf("No\n"); return 0; }
	}
	
	if (ds < 0 || dt < 0) { printf("No\n"); return 0; }
	printf("Yes\n");
	vep(i,ans) printf("%d %d\n", ans[i].first, ans[i].second);

	return 0;
}

posted @ 2016-10-05 12:14  Armeria  阅读(346)  评论(0编辑  收藏  举报