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;
}

浙公网安备 33010602011771号