[BZOJ1098][POI2007]办公楼biu
题目描述
\(FGD\)开办了一家电话公司。
他雇用了\(N\)个职员,给了每个职员一部手机。
每个职员的手机里都存储有一些同事的电话号码。
由于\(FGD\)的公司规模不断扩大,旧的办公楼已经显得十分狭窄,\(FGD\)决定将公司迁至一些新的办公楼。
\(FGD\)希望职员被安置在尽量多的办公楼当中,这样对于每个职员来说都会有一个相对更好的工作环境。
但是,为了联系方便起见,如果两个职员被安置在两个不同的办公楼之内,他们必须拥有彼此的电话号码。
Input
第一行包含两个整数\(N(2<=N<=100000)\)和\(M(1<=M<=2000000)\)。
职员被依次编号为\(1,2,……,N\).以下\(M\)行,每行包含两个正数\(A\)和\(B(1<=A<b<=n)\),表示职员\(a\)和\(b\)拥有彼此的电话号码),\(li <= 1000\)
Output
包含两行。第一行包含一个数\(S\),表示\(FGD\)最多可以将职员安置进的办公楼数。
第二行包含\(S\)个从小到大排列的数,每个数后面接一个空格,表示每个办公楼里安排的职员数。
Sample Input
7 16
1 3
1 4
1 5
2 3
3 4
4 5
4 7
4 6
5 6
6 7
2 4
2 7
2 5
3 5
3 7
1 7
Sample Output
3
1 2 4
链表优化广搜。。。
由题意得,即找到补图的每个连通块个数。
观察数据范围,点数很少,但是边数却很多。
直接暴力广搜肯定会炸裂。
那我们有两种选择,并查集或优化广搜。
并查集肯定很麻烦,那我们选择了优化广搜。
我们发现广搜的复杂度都堆积到了枚举点上面。
于是,我们要想办法去优化这一过程。
怎么优化呢?
我们需要一个数据结构,支持遍历所有的点,并支持删除操作。
是什么呢?
链表!!!
我们一开始将所有点都放进链表里。
每遍历了一个点就将该点从链表中删除。
由此优化广搜。
代码如下
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
#define reg register
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,e) for(reg int i=H[e];i;i=G[i].nxt)
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define int long long
inline int Read() {
int res=0,f=1;
char c;
while(c=getchar(),c<48||c>57)if(c=='-')f=0;
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>=48&&c<=57);
return f?res:-res;
}
template<class T>inline bool Min(T &a,T const&b) {
return a>b?a=b,1:0;
}
template<class T>inline bool Max(T &a,T const&b) {
return a<b?a=b,1:0;
}
const int N=1e5+5,M=2e6+5;
int n,m,Ans,tot,H[N],Sz[N],mark[N],vis[N],L[N],R[N];
struct edge {
int nxt,to;
} G[M<<1];
void Add(int a,int b) {
G[++tot]=(edge)<%H[a],b%>,H[a]=tot;
}
void Del(int x) {
vis[x]=1,L[R[x]]=L[x],R[L[x]]=R[x];
}
void BFS(int x) {
queue<int>Q;
Q.push(x);
while(!Q.empty()) {
Sz[Ans]++;
int x=Q.front();
Q.pop();
int o=0;
for(reg int i=H[x]; i; i=G[i].nxt)mark[G[i].to]=1,o++;
for(reg int i=R[0]; i; i=R[i]) {
if(vis[i]||mark[i])continue;
Q.push(i),Del(i);
}
for(reg int i=H[x]; i; i=G[i].nxt)mark[G[i].to]=0;
}
}
signed main() {
n=Read(),m=Read();
rep(i,1,m) {
int a=Read(),b=Read();
Add(a,b),Add(b,a);
}
rep(i,0,n)L[i]=i-1,R[i]=i+1;
R[n]=0;
rep(i,1,n)if(!vis[i])Ans++,Del(i),BFS(i);
printf("%d\n",Ans);
sort(Sz+1,Sz+Ans+1);
rep(i,1,Ans)printf("%d ",Sz[i]);
}