bzoj1098 [POI2007]办公楼biu(图论+list)

给出补图,求原图的连通块个数及大小。
我们直接bfs原图,每次把补图中的边(也就是原图完全图中被删掉的边)通向的点打上标记,这样没被标记的点就是与此点连通的,都在一个连通块内,用链表优化一下,支持 O ( 1 ) O(1) O(1)插入删除。
每个点在链表中只会被删一次,所以这部分复杂度是 O ( n ) O(n) O(n)的,每次给补图中的边连接的点打标记是 O ( m ) O(m) O(m)的,因此总的复杂度是 O ( n + m ) O(n+m) O(n+m)的,可以过。

#include 
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
#define M 2000010
int n,m,h[N],num=0;
struct edge{
	int to,nxt;
}data[M<<1];
list<int>li;
list<int>::iterator it,it1;
queue<int>q;
vector<int>ans;
bool f[N];
int main(){
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout); 
	scanf("%d%d",&n,&m);
	while(m--){
		int x,y;scanf("%d%d",&x,&y);
		data[++num].to=y;data[num].nxt=h[x];h[x]=num;
		data[++num].to=x;data[num].nxt=h[y];h[y]=num;
	}for(int i=1;i<=n;++i) li.push_back(i);
	while(!li.empty()){
		int res=0;q.push(li.front());li.pop_front();
		while(!q.empty()){//bfs cc
			int x=q.front();q.pop();++res;
			for(int i=h[x];i;i=data[i].nxt)	f[data[i].to]=1;//deleted
			for(it=li.begin();it!=li.end();){
				if(!f[*it]){//connected -> in the same component
					q.push(*it);it1=it;++it;li.erase(it1);
				}else ++it;
			}for(int i=h[x];i;i=data[i].nxt)	f[data[i].to]=0;
		}ans.push_back(res);
	}sort(ans.begin(),ans.end());
	printf("%d\n",(int)ans.size());
	for(int i=0;i<ans.size();++i) printf("%d%c",ans[i],i==ans.size()-1?'\n':' ');
	return 0;
}

你可能感兴趣的:(bzoj,STL)