【Codeforces Round 375 (Div 2) F】【构造 贪心】st-Spanning Tree 树的特殊最小生成树使得S度不超SD,T度不超TD

来源:互联网 发布:js 打开新url 编辑:程序博客网 时间:2024/06/05 08:04
F. st-Spanning Tree
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given an undirected connected graph consisting of n vertices and m edges. There are no loops and no multiple edges in the graph.

You are also given two distinct vertices s and t, and two values ds and dt. Your task is to build any spanning tree of the given graph (note that the graph is not weighted), such that the degree of the vertex s doesn't exceed ds, and the degree of the vertex t doesn't exceed dt, or determine, that there is no such spanning tree.

The spanning tree of the graph G is a subgraph which is a tree and contains all vertices of the graph G. In other words, it is a connected graph which contains n - 1 edges and can be obtained by removing some of the edges from G.

The degree of a vertex is the number of edges incident to this vertex.

Input

The first line of the input contains two integers n and m (2 ≤ n ≤ 200 000, 1 ≤ m ≤ min(400 000, n·(n - 1) / 2)) — the number of vertices and the number of edges in the graph.

The next m lines contain the descriptions of the graph's edges. Each of the lines contains two integers u and v (1 ≤ u, v ≤ n, u ≠ v) — the ends of the corresponding edge. It is guaranteed that the graph contains no loops and no multiple edges and that it is connected.

The last line contains four integers s, t, ds, dt (1 ≤ s, t ≤ n, s ≠ t, 1 ≤ ds, dt ≤ n - 1).

Output

If the answer doesn't exist print "No" (without quotes) in the only line of the output.

Otherwise, in the first line print "Yes" (without quotes). In the each of the next (n - 1) lines print two integers — the description of the edges of the spanning tree. Each of the edges of the spanning tree must be printed exactly once.

You can output edges in any order. You can output the ends of each edge in any order.

If there are several solutions, print any of them.

Examples
input
3 31 22 33 11 2 1 1
output
Yes3 21 3
input
7 87 41 35 45 73 22 46 11 26 4 1 4
output
Yes1 35 73 27 42 46 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 ls o<<1#define rs o<<1|1typedef 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 = 2e5 + 10, M = 4e5+10, Z = 1e9 + 7, inf = 0x3f3f3f3f;template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }int n, m;pair<int, int>a[M];int S, T, SD, TD;int f[N];bool s[N], t[N];int find(int x){return f[x] == x ? x : f[x] = find(f[x]);}int con[N];pair<int, int>ans[M];bool solve(){//第一步,做基础联通并判定int g = 0;int ST = 0;for (int i = 1; i <= m; ++i){int x = a[i].first;int y = a[i].second;if (y == S)swap(x, y);if (x == S && y == T)++ST;else if (x == S)s[find(y)] = 1;else{if (y == T)swap(x, y);if (x == T)t[find(y)] = 1;else{x = find(x);y = find(y);if (x != y){f[y] = x;s[x] |= s[y];t[x] |= t[y];ans[++g] = a[i];}}}}//第二步,做合法性判定int both = 0;int SPE = 0;MS(con, 0);--SD;--TD;for (int i = 1; i <= n; ++i)if (i != S && i != T && i == find(i)){if (s[i] && t[i]){if (SPE == 0)SPE = i;else con[i] = -1, ++both;}else if (s[i]){if (--SD < 0)return 0;con[i] = S;}else if (t[i]){if (--TD < 0)return 0;con[i] = T;}else return 0;}int can = SD + TD;if (can < both)return 0;//第三步,贪心决策if (SPE){int sta = 3;for (int i = 1; i <= m; ++i){int x = a[i].first;int y = a[i].second;int fx = find(x);int fy = find(y);if (fy == SPE)swap(fx, fy), swap(x, y);if (fx == SPE){if ((sta & 1) && y == S){sta ^= 1;ans[++g] = a[i];}else if ((sta & 2) && y == T){sta ^= 2;ans[++g] = a[i];}}}}else ans[++g] = { S,T };for (int i = 1; i <= m; ++i){int x = a[i].first;int y = a[i].second;if (y == S)swap(x, y);if (x == S && y == T);else if (x == S){int fy = find(y);if (con[fy] == S)//要和S连{ans[++g] = a[i];con[fy] = 0;}else if (con[fy] == -1 && SD)//可以和S连{con[fy] = 0;ans[++g] = a[i];--SD;}}else{if (y == T)swap(x, y);if (x == T){int fy = find(y);if (con[fy] == T)//要和T连{ans[++g] = a[i];con[fy] = 0;}else if (con[fy] == -1 && TD)//可以和T连{con[fy] = 0;ans[++g] = a[i];--TD;}}}}puts("Yes");for (int i = 1; i <= g; ++i)printf("%d %d\n", ans[i].first, ans[i].second);return 1;}int main(){while (~scanf("%d%d", &n, &m)){for (int i = 1; i <= m; ++i)scanf("%d%d", &a[i].first, &a[i].second);scanf("%d%d%d%d", &S, &T, &SD, &TD);for (int i = 1; i <= n; ++i){s[i] = 0;t[i] = 0;f[i] = i;}if (!solve())puts("No");}return 0;}/*【trick&&吐槽】自己做题就是太不慌不忙了,导致最后差一点点时间没写完,把一个错误的代码交过去竟然就过了初测。然而最后还是wa on test50还有,变量定义一定要结构统一化,不然可能会不小心写错=w=【题意】给你一个联通无向图让你构造一个子图,使得——1,该子图是一棵树2,S点的度数不超过SD3,T点的度数不超过TD【类型】构造【分析】一,我们把点的两端都不是S或T的边取出来,用并查集连起来。二,这个过程中我们同时维护——哪些集合可以和S连边哪些集合可以和T连边哪些集合可以和S、T都连边S与T之间是否有边三,判定合法性——重新扫一遍所有集合如果该集合只能和S连边,就与S连,度数超额GG,否则标记该集合与S连如果该集合只能和T连边,就与T链,度数超额GG,否则标记该集合与T连如果该集合能和S与T都连边,则标记该集合可以与S和T联通,记做both这个时候,SD和TD都会有一个剩余度数,之和记做can如果剩余联通块个数(就是还没有和S或T任意一个连接的)超过了剩余度数(即both>can),也GG判定还未结束——如果存在both,即存在一个集合可以与S和T都连边,那我们就在这个集合的身上实现其余S和T的连边这样使得S与T连边了,我们多消耗的额外度数为1否则,不存在一个集合与S和T之间连边,那我们就要在S和T之间通过ST边直接连接。这样时而S与T连边了,我们多消耗的额外度数为2显然要最后万不得已才考虑ST边因为S与T的联通必然要消耗两者的度各1点。所以我们可以一开始就对两者的度做-1操作存在both找到一个可以与S和T都联通的联通块做联通操作不存在both则连ST边对于其他可以和S与T都联通的联通块,我们在保证正确的情况下连边即可。【时间复杂度&&优化】O(m)*/


0 0