Solution - P3452 [POI 2007] BIU-Offices

咕。好神奇的题。

思路

不难看出题目要求求补图的联通块。这不就没救了吗

不难看出在原图中没有边即在补图中有边,于是维护一个集合,每次对于一个节点在集合里找到没有直连边的点,并加入联通块就行了。对于一个联通块 DFS 或 BFS。

集合可以用链表维护。

代码

#include <bits/stdc++.h>
#define rint register int
#define rllong register long long
#define llong long long
#define N 100005
#define M 5000006
using namespace std;

int to[M], nxt[M], head[N], gsiz = 1;
#define mkarc(u,v) (++gsiz, to[gsiz]=v, nxt[gsiz]=head[u], head[u]=gsiz)
int pr[N], nx[N], he;
int vis[N], tmp[N];
int scc[N], cnt;
int n, m;

struct Queue{
	int que[N], he = 1, ta;
	int  head()      {return que[he];}
	void pop()       {++he;}
	void push(rint x){que[++ta] = x;}
	bool empty()     {return he > ta;}
} q;

int main(){
	scanf("%d %d", &n, &m);
	for(rint i = 1; i <= m; ++i){
		rint u, v;
		scanf("%d %d", &u, &v);
		mkarc(u, v), mkarc(v, u);
	}
	he = 1;
	for(rint i = 1; i <= n; ++i) nx[i-1] = i, pr[i+1] = i;
	while(he){
		q.push(he), he = nx[he], pr[he] = 0;
		++cnt;
		while(!q.empty()){
			++scc[cnt];
			rint u = q.head(); q.pop();
			for(rint i = head[u]; i; i = nxt[i])
				tmp[to[i]] = true;
			for(rint i = he; i; i = nx[i]){
				if(!tmp[i]){
					if(i == he) he = nx[he];
					nx[pr[i]] = nx[i], pr[nx[i]] = pr[i];
					q.push(i);
				}
				else tmp[i] = false;
			}
		}
	}
	sort(scc+1, scc+cnt+1);
	printf("%d\n", cnt);
	for(rint i = 1; i <= cnt; ++i) printf("%d ", scc[i]);
	return 0;
}

posted @ 2025-06-02 10:13  Hootime  阅读(11)  评论(1)    收藏  举报