[CF1019C]Sergey's problem[构造]

题意

找出一个集合 \(Q\),使得其中的点两两之间没有连边,且集合中的点可以走不超过两步到达其他所有不在集合中的点。输出任意一组解。

\(n\leq 10^6\)

分析

  • 考虑构造,先从 \(1\)\(n\) 枚举是否存在一个点 \(u\) 还没有被标记过,如果没有就用 \(u\) 去标记能够走到的点,同时将 \(u\) 加入 \(Q\)
    容易证明这样的构造方式能够保证条件2:如果 \(u\) 的入度为 0 那么一定会加入 \(Q\) ,否则如果不在 \(Q\) 中就一定有一个能够到 \(u\) 的点在 \(Q\) 中。

  • 但是顺次枚举就有可能使得“相邻编号大的点能到编号小的点,两个点都在 \(Q\) 中” 这种情况,所以考虑如果出现了这样两个点,我们将编号较大的点保留,能够保证 \(Q\) 中的点在两步以内到达所有点。

  • 总时间复杂度为 \(O(n)\)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
inline int gi() {
    int x = 0,f = 1;
    char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x << 3) + (x << 1) + ch - 48;
        ch = getchar();
    }
    return x * f;
}
template <typename T> inline void Max(T &a, T b){if(a < b) a = b;}
template <typename T> inline void Min(T &a, T b){if(a > b) a = b;}
const int N = 1e6 + 7;
int n, m, edc, ans;
int vis[N], mark[N], head[N];
struct edge {
    int lst, to;
    edge(){}edge(int lst, int to):lst(lst), to(to){}
}e[N*2];
void Add(int a, int b) {
    e[++edc] = edge(head[a], b), head[a]=edc;
}
vector<int> res;
int main(){
    n = gi(), m = gi();
    rep(i, 1, m) {
        int x = gi(), y = gi();
        Add(x, y);
    }
    rep(u, 1, n) if(!vis[u]){
        mark[u] = vis[u] = 1;
        go(u) vis[v] = 1;
    }
    for(int u = n; u; --u) if(mark[u]){
        ++ans;
        go(u) mark[v] = 0;
    }
    for(int u = 1; u <= n; ++u) if(mark[u]) res.pb(u);
    printf("%d\n", ans); 
    for(int i = 0; i < res.size(); ++i) {
        printf("%d%c",res[i],i == res.size() - 1 ? '\n' : ' ');
    }
    return 0;
}

转载于:https://www.cnblogs.com/yqgAKIOI/p/10109273.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值