orzLYF大佬,太强了,做的题目总是那么的有思想,不愧是一代神犇。
我突然发现我的代码跑的还是挺快的,这题在BZOJ上拿了rk14。
画风突变——但是那个第一是什么鬼?!
这TMD有毒吧?!(忍不住吐槽了一下BZOJ,这不是瞎搞吗?不愧是“爆炸OJ”……)
好了,我们该讲题目了。(正经脸)
这题的n的范围是100000,O(n^2)的算法就直接pass了,只能骗骗分。
其实这题说白了就是求连通块的数量,不过这个连通块不是题目给出的关系的连通块,而是题目给出的关系的补集的连通块。(说的这么绕……)
简单来讲,就是把题目给出的关系都打断,然后没给出的关系连起来就行了。
可惜这样的时间复杂度还是O(n^2)的……
这时我们就想到了链表,初始化时把所有节点都链起来,然后每次确定一个节点在一个连通块中时,就把这个节点从链表中删掉。
这样我们就把时间复杂度降低了很多了,至少过这题是没有问题的。
附上AC代码:
#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#include <queue>
#define N 100010
using namespace std;
vector <int> map[N];
queue <int> que;
int n,m,x,y,len,ans[N],l[N],r[N];
bool b[N],bo[N];
inline char nc(){
static char ch[100010],*p1=ch,*p2=ch;
return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &a){
static char c=nc();int f=1;
for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
for (a=0;isdigit(c);a=a*10+c-'0',c=nc());
a*=f;return;
}
inline void del(int x){
r[l[x]]=r[x];
l[r[x]]=l[x];
b[x]=1;
return;
}
inline void bfs(int x){
while (!que.empty()) que.pop();
que.push(x),++len;
while (!que.empty()){
int p=que.front();que.pop(),++ans[len];
for (int i=0; i<map[p].size(); ++i) bo[map[p][i]]=1;
for (int i=r[0]; i; i=r[i]) if (!b[i]&&!bo[i]) que.push(i),del(i);
for (int i=0; i<map[p].size(); ++i) bo[map[p][i]]=0;
}
return;
}
int main(void){
read(n),read(m);
for (int i=1; i<=m; ++i){
read(x),read(y);
map[x].push_back(y);
map[y].push_back(x);
}
for (int i=1; i<=n; ++i) l[i]=i-1,r[i]=i+1;
r[n]=0;
for (int i=1; i<=n; ++i)
if (!b[i]) del(i),bfs(i);
sort(ans+1,ans+1+len);
printf("%d\n",len);
for (int i=1; i<=len; ++i) printf("%d ",ans[i]);
return 0;
}