洛谷比赛T2萨塔尼亚的一生之敌(sataniya)

前言

题目难懂

题面


有点难懂

sol

四十分相当好拿。
暴力n^2枚举两两之间有没有边。
然后考虑优化到100.
注意到复杂度的瓶颈在于有许多无效枚举。也就是说枚举到了两个点没有边但已经在一个集合里.
有注意到复杂度可优化地方在于与自己没有边的太多,与自己有边的太少。所以换一个方法枚举。

code

// luogu-judger-enable-o2
#include
using namespace std;
inline int read(){
    register int data=0;
    register char ch=0;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch<='9'&&ch>='0')data=(data<<3)+(data<<1)+(ch^48),ch=getchar();
    return data;
}
const int _ =2e6+55;
const int __ = 1e5+3;
struct edge{
    int nt,to;
}e[_<<1];
int hjt[__],lk,head[__],cnt,n,m,parent[__],rec[__],yyb,ans[_];
inline void add(register int a,register int b){
    e[++cnt].nt=head[a],e[cnt].to=b,head[a]=cnt;
}
int fi(register int x){
    if(x==parent[x])return x;
    parent[x]=fi(parent[x]);
    return parent[x];
}
void akk(register int rt){
    lk++;
    for(register int i=head[rt];i;i=e[i].nt)hjt[e[i].to]=lk;
    for(register int i=1;i<=n;++i){
        if(rt==i)continue;
        if(hjt[i]==lk)continue;
        int op=fi(i);
        parent[op]=rt;
    }
}
bool cmp(register int a,register int b){return aint main(){
    //freopen("data.in","r",stdin);

    n=read(),m=read();
    for(register int i=1;i<=m;++i){
        int a=read(),b=read();
        add(a,b),add(b,a);      
    }
    for(register int i=1;i<=n;++i)parent[i]=i;
    for(register int i=1;i<=n;++i)
        if(parent[i]==i)
            akk(i);
    for(register int i=1;i<=n;++i)
    {
        ++ans[fi(i)];
    }
    for(register int i=1;i<=n;++i){
        if(ans[i])hjt[++yyb]=ans[i];
    }
    sort(hjt+1,hjt+yyb+1,cmp);
    printf("%d\n",yyb);
    for(register int i=1;i<=yyb;++i)printf("%d ",hjt[i]);
}

你可能感兴趣的:(图论,题解)