Codeforces Round #375 (Div. 2) -- F. st-Spanning Tree(并查集 构造生成树)

大体题意:

给你一个无向图,要求构造出一个生成树来,使得s,t 的度数不超过ds 和dt,多解任意输出!

思路:

很好的一道题目,请教了学长!

先把s和t结点去掉,构造出多个连通块来,然后依次于s和t 相连!

既能连s又能连t的联通块是比较好的,最后在处理,先把那些只能连接一个节点的联通快先连起来,并且计数统计!

然后在根据当前的计数来加那些万能联通块。

注意:

细节比较多,说几个方面:

1.  某个联通块是万能的  不是存在一个节点既能连s和t,而是存在1个以上就行,就是第一个连s,第二个连t!

2. 仔细处理万能连通块。

3.  还需要判断s和t 需不需要直接相连!

代码写的很乱 参考以下吧:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 400000 + 10;
struct Node{
    int u,v;
    void read(){
        scanf("%d %d",&u, &v);
    }
}p[maxn];
int fa[maxn];
set<int>g[2];
set<int>bing[maxn>>1];
set<int>::iterator it;
vector<pair<int,int> > ans;
vector<pair<int,int> > Do;
int find(int x){
    return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}
void add(int x,int y){
    int xx = find(x);
    int yy = find(y);
    if (xx != yy){
        if (xx > yy)swap(xx,yy);
        fa[yy] = xx;
    }
}
int n,m;
int s,t,ds,dt;
bool ok(){
    for (int i = 0; i <= n; ++i)fa[i] = i;
    for (int i = 0; i < m; ++i){
        add(p[i].u,p[i].v);
    }
    for (int i = 1; i <= n; ++i){
        if (find(i) != find(1))return false;
    }
    return true;
}
bool cmp(set<int>& a_,set<int>& b_){
    return a_.size() > b_.size();
}
int main(){
    bool okst = 0;
    scanf("%d %d",&n, &m);
    for (int i = 0; i < m; ++i){
        p[i].read();
    }
    scanf("%d %d %d %d",&s, &t, &ds, &dt);
    int ts = 0,tt = 0;
    if (!ok()){
        return 0 * puts("No");
    }
    for (int i = 0; i <= n; ++i)fa[i] = i;
    for (int i = 0; i < m; ++i){
        int u = p[i].u, v = p[i].v;
        if (u == s)g[0].insert(v);
        if (v == s)g[0].insert(u);
        if (v == t)g[1].insert(u);
        if (u == t)g[1].insert(v);
        if (u == s && v == t || u == t && v == s)okst = 1;
        if (u == s || u == t || v == t || v == s)continue;
        if (find(u) != find(v)){
            add(u,v);
            ans.push_back(make_pair(u,v));
        }
    }
    for (int i = 1; i <= n; ++i){
        if (i == s || i == t)continue;
        int f = find(i);
        bing[f].insert(i);
    }
    sort(bing+1,bing+n+1,cmp);
    for (int i = 1; i <= n; ++i){
        if ((int)bing[i].size() == 0)break;
        int oks = -1,okt = -1;
        for (it = bing[i].begin(); it != bing[i].end(); ++it){
            int tm = *it;
            if (g[0].count(tm)){
                oks = tm;
                break;
            }
        }
        for (it = bing[i].begin(); it != bing[i].end(); ++it){
            int tm = *it;
            if (g[1].count(tm)){
                okt = tm;
                break;
            }
        }
        if (oks != -1 && okt != -1)Do.push_back(make_pair(oks,okt));
        else if (oks != -1){
            ++ts;
            add(oks,s);
            ans.push_back(make_pair(oks,s));
        }
        else if (okt != -1){
            ++tt;
            add(okt,t);
            ans.push_back(make_pair(okt,t));
        }
    }
    int len = Do.size();
    for (int i = 0; i < len; ++i){
        if (ts < ds){
            ++ts;
            ans.push_back(make_pair(Do[i].first,s));
            add(s,Do[i].first);
            Do[i].first = -1;
        }
        else {
            ++tt;
            ans.push_back(make_pair(Do[i].second,t));
            add(t,Do[i].second);
            Do[i].second = -1;
        }
    }
    if (find(s) != find(t) && ts <= ds && tt <= dt){
        bool flag = 0;
        int len = Do.size();
        for (int i = 0; i < len; ++i){
            if (ts < ds && Do[i].first != -1){
                ++ts;
                flag = 1;
                add(Do[i].first,s);
                ans.push_back(make_pair(Do[i].first,s));
                break;
            }
            else if (Do[i].second != -1){
                ++tt;
                flag = 1;
                add(Do[i].second,t);
                ans.push_back(make_pair(Do[i].second,t));
                break;
            }

        }
        if (!flag && okst){
            add(s,t);
            ++ts,++tt;
            ans.push_back(make_pair(s,t));
        }


    }
    if (find(s)==find(t) && ts <= ds && tt <= dt) {
        puts("Yes");
        int hi = ans.size();
        for (int i = 0; i < hi; ++i){
            printf("%d %d\n",ans[i].first,ans[i].second);
        }
    }
    else puts("No");

    return 0;
}
/**
3 2
2 1
3 1
1 2 1 1

10 15
3 2
9 3
9 4
7 3
9 1
5 9
9 8
7 5
5 2
4 3
6 8
7 9
9 10
9 6
5 6
5 9 1 3
**/

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 0001 ≤ 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 ≤ nu ≠ 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 stdsdt (1 ≤ s, t ≤ ns ≠ t1 ≤ 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 3
1 2
2 3
3 1
1 2 1 1
output
Yes
3 2
1 3
input
7 8
7 4
1 3
5 4
5 7
3 2
2 4
6 1
1 2
6 4 1 4
output
Yes
1 3
5 7
3 2
7 4
2 4
6 1


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值