Cddeforces 723F - st-Spanning Tree(构造,无权生成树)

题目:http://codeforces.com/contest/723/problem/F
题意:

给你一个联通无向图
让你构造一个无权生成树,使得——
S点的度数不超过SD
T点的度数不超过TD

分析:

这题和上一题一样都是构造(灵机一动~~)
首先把不包含s和t的边先求一下连通块
处理完后还剩三种边
s-某个连通块 t-某个连通块 s-t
然后对于某个连通块只与s有边,那么连接,t同理
如果某个既可以和s连也可以和t连,那么就分别和s,t连来保持连通
最后连s-t的边
如果到最后图都不连通或者s和t的度不满足,那么无解
否则有解

代码:

#include <bits/stdc++.h>
using namespace std;
const int MAX=4e5+9;
int a[MAX],b[MAX],s,t,ds,dt,n,m,fa[MAX];
bool ms[MAX],mt[MAX];
vector<int> vs,vt;
vector<pair<int,int> > ans;
int findfa(int x){return fa[x]==x?x:fa[x]=findfa(fa[x]);}

void merge(int a,int b) {
    if (a==s) ds--;
    if (a==t) dt--;
    fa[findfa(a)]=findfa(b),ans.push_back(make_pair(a,b));
}
int main() {

    ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for (int i=1; i<=n; i++) fa[i]=i;
    for (int i=1; i<=m; i++) cin>>a[i]>>b[i];
    cin>>s>>t>>ds>>dt;
    for (int i=1; i<=m; i++)
        if (a[i]!=s && a[i]!=t && b[i]!=s && b[i]!=t) {
            if (findfa(a[i])!=findfa(b[i]))
                merge(a[i],b[i]);
        } else {
            if (a[i]==s) vs.push_back(b[i]);
            if (b[i]==s) vs.push_back(a[i]);
            if (a[i]==t) vt.push_back(b[i]);
            if (b[i]==t) vt.push_back(a[i]);
        }
    for (int i=0; i<vs.size(); i++) ms[findfa(vs[i])]=1;
    mt[t]=1,ms[s]=1;
    for (int i=0; i<vt.size(); i++) {
        int x=vt[i];
        mt[findfa(x)]=1;
        if (!ms[findfa(x)] && findfa(x)!=findfa(t))
            merge(x,t),dt--;
    }
    for (int i=0; i<vs.size(); i++) {
        int x=vs[i];
        if (!mt[findfa(x)] && findfa(x)!=findfa(s))
            merge(x,s),ds--;
    }
    for (int i=0; i<vs.size(); i++) {
        int x=vs[i];
        if (findfa(x)!=findfa(s) && findfa(x)!=findfa(t) && ds)
            merge(x,s),ds--;
    }
    for (int i=0; i<vt.size(); i++) {
        int x=vt[i];
        if (findfa(x)!=findfa(s) && findfa(x)!=findfa(t))
            merge(x,t),dt--;
    }
    for (int i=0; i<vs.size(); i++) {
        int x=vs[i];
        if (x==t && !dt) ;
        else if (findfa(x)!=findfa(s) && ds)
            merge(x,s),ds--;
    }
    for (int i=0; i<vt.size(); i++) {
        int x=vt[i];
        if (x==s && !ds) ;
        else if (findfa(x)!=findfa(t))
            merge(x,t),dt--;
    }
    bool flg=0;
    for (int i=2; i<=n; i++) if (findfa(i)!=findfa(1)) flg=1;
    if (dt<0 || ds<0 || flg) return cout<<"No\n",0;
    cout<<"Yes\n";
    for (int i=0; i<ans.size(); i++) cout<<ans[i].first<<" "<<ans[i].second<<'\n';
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值