Codeforces Educational Codeforces Round 37 E

You are given an undirected graph consisting of n vertices and edges. Instead of giving you the edges that exist in the graph, we give you m unordered pairs (x, y) such that there is no edge between x and y, and if some pair of vertices is not listed in the input, then there is an edge between these vertices.

You have to find the number of connected components in the graph and the size of each component. A connected component is a set of vertices X such that for every two vertices from this set there exists at least one path in the graph connecting these vertices, but adding any other vertex to X violates this rule.

Input
The first line contains two integers n and m (1 ≤ n ≤ 200000, ).

Then m lines follow, each containing a pair of integers x and y (1 ≤ x, y ≤ n, x ≠ y) denoting that there is no edge between x and y. Each pair is listed at most once; (x, y) and (y, x) are considered the same (so they are never listed in the same test). If some pair of vertices is not listed in the input, then there exists an edge between those vertices.

Output
Firstly print k — the number of connected components in this graph.

Then print k integers — the sizes of components. You should output these integers in non-descending order.

Example
input
5 5
1 2
3 4
3 2
4 2
2 5
output
2
1 4
题目是给你一个图,让你求这个图的反图的联通块个数和大小,这道题我们当然不能耿直的直接建一个反图,因为这个图是稀疏图,那么他的反图肯定是稠密图。我们可以遍历每一个点,对于每一个点,找到与他不相邻的且以前没有被访问过的点,加入队列,然后bfs,与他说明两点之间不相连,说明原图之间肯定相连,把他加入后说明这两个点肯定在一个联通块里,被访问过就说明已经被加到一个联通块里了,但这里我们还是O(n^2)的复杂度,我们这时可以用链表优化bfs,因为每个点要找到没有与之相邻的点,所以我们可以把所有点加入到链表中,在使用过这个点之后在链表中删去,这样复杂度就降到了O(n+m)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
vector<int>E[maxn];
vector<int>ans;
bool vis[maxn],book[maxn];
list<int>lists;
int bfs(int x) {
    queue<int>Q;
    Q.push(x);
    int num=0;
    while(!Q.empty()) {
        int now=Q.front();
        Q.pop();
        if(vis[now]) continue;
        vis[now]=true,num++;
        for(auto &it:E[now]) book[it]=true;
        for(auto it=lists.begin();it!=lists.end();it++) {
            int v=*it;
            if(!book[v]) {
                Q.push(v);
                lists.erase(it);
            }
        }
        for(auto &it:E[now]) book[it]=false;
    }
    return num;
}


int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m,x,y;
    cin>>n>>m;
    for(int i=1;i<=n;i++)lists.push_back(i);
    for(int i=1;i<=m;i++) {
        cin>>x>>y;
        E[x].push_back(y);
        E[y].push_back(x);
    }
    for(int i=1;i<=n;i++) {
        if(!vis[i]) ans.push_back(bfs(i));
    }
    sort(ans.begin(),ans.end());
    cout<<ans.size()<<endl;
    for(auto it:ans) cout<<it<<" ";
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值