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.
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).
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.
3 3 1 2 2 3 3 1 1 2 1 1
Yes 3 2 1 3
7 8 7 4 1 3 5 4 5 7 3 2 2 4 6 1 1 2 6 4 1 4
Yes 1 3 5 7 3 2 7 4 2 4 6 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|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 = 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点的度数不超过SD
3,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)
*/