1. 程式人生 > 實用技巧 >[CF920E] Connected Components? - 思維,並查集,STL

[CF920E] Connected Components? - 思維,並查集,STL

Description

給出一個 \(n\) 個點,\(\frac{n(n-1)}{2}-m\) 的無向圖,以補圖的形式輸入,問圖中有多少連通分量以及每個連通分量有多少點。

Solution

考慮增量構造,依次加入每一個點,維護已有的連通塊。對於每一個新加入的帶點,考察其餘某一個已有的連通塊是否連通,這隻需要數一下邊的條數即可,如果連通則並查集維護一下。容易發現連通塊數量一定是很小的。

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1000005;

int fa[N],sz[N],n,m,t1,t2;
vector <int> g[N];

int find(int p)
{
    return p==fa[p] ? p : fa[p]=find(fa[p]);
}

set<int> s;

void merge(int p,int q)
{
    p=find(p);
    q=find(q);
    if(p>q) swap(p,q);
    if(p!=q) sz[q]+=sz[p],fa[p]=q;
}

signed main()
{
    //ios::sync_with_stdio(false);

    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
        sz[i]=1;
    }
    for(int i=1;i<=m;i++)
    {
        cin>>t1>>t2;
        if(t1>t2) swap(t1,t2);
        g[t2].push_back(t1);
    }

    for(int i=1;i<=n;i++)
    {
        map<int,int> mp;
        for(int j:g[i])
        {
            mp[find(j)]++;
        }
        vector <int> vec;
        for(int j:s)
        {
            if(find(j)==j && mp[j]<sz[j])
            {
                vec.push_back(j);
            }
        }
        for(int j:vec)
        {
            merge(i,j);
        }
        vec.clear();
        for(int j:s)
        {
            if(find(j)!=j) vec.push_back(j);
        }
        for(int j:vec)
        {
            s.erase(j);
        }
        if(find(i)==i) s.insert(i);
        /*for(int j:s)
        {
            cout<<j<<",";
        }
        cout<<endl;*/
    }

    multiset <int> ans;
    for(int i:s)
    {
        ans.insert(sz[i]);
    }
    cout<<ans.size()<<endl;
    for(int i:ans)
    {
        cout<<i<<" ";
    }
}