【bzoj1098】 [POI2007]办公楼biu
题目描述:
FGD开办了一家电话公司。他雇用了N个职员,给了每个职员一部手机。每个职员的手机里都存储有一些同事的电话号码。由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决定将公司迁至一些新的办公楼。 FGD希望职员被安置在尽量多的办公楼当中,这样对于每个职员来说都会有一个相对更好的工作环境。但是,为了联系方便起见,如果两个职员被安置在两个不同的办公楼之内,他们必须拥有彼此的电话号码。
输入:
第一行包含两个整数N(2<=N<=100000)和M(1<=M<=2000000)。职员被依次编号为1,2,……,N. 以下M行,每行包含两个正数A和B(1<=A
输出:
包含两行。第一行包含一个数S,表示FGD最多可以将职员安置进的办公楼数。第二行包含S个从小到大排列的数,每个数后面接一个空格,表示每个办公楼里安排的职员数。
样例输入:
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
样例输出:
3
1 2 4
题解:
求补图的联通块个数。首先我们注意到,n<=100000,m<=2000000,m远小于n的完全图的边的个数。
如果找出所有补图的边显然是不行的。所以我们用floodfill来搞,对于每个没有访问的点每次找到这个点不能遍历到的点,然后入队。
最后,一定一定要用链表来优化每次遍历所有的点。
代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #ifdef WIN32 #define LL "%I64d" #else #define LL "%lld" #endif #ifdef CT #define debug(...) printf(__VA_ARGS__) #define setfile() #else #define debug(...) #define filename "" #define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout); #endif #define R register #define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++) #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b)) #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b)) #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0) #define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0) char B[1 << 15], *S = B, *T = B; inline int FastIn() { R char ch; R int cnt = 0; R bool minus = 0; while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ; ch == '-' ? minus = 1 : cnt = ch - '0'; while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0'; return minus ? -cnt : cnt; } #define maxn 100010 #define maxm 4000010 int ans[maxn], cnt, next[maxn], prev[maxn]; bool vis[maxn]; struct Edge { int to; Edge *next; }e[maxm], *ecnt = e, *last[maxn]; inline void link(R int a, R int b) { *++ecnt = (Edge){b, last[a]}; last[a] = ecnt; *++ecnt = (Edge){a, last[b]}; last[b] = ecnt; } int q[maxn], n, m; bool con[maxn]; inline void del(R int x) { next[prev[x]] = next[x]; prev[next[x]] = prev[x]; } inline void floodfill(R int x) { R int head = 0, tail = 1; q[1] = x; vis[x] = 1; while (head < tail) { head++; R int now = q[head]; for (R Edge *iter = last[now]; iter; iter = iter -> next) con[iter -> to] = 1; for (R int i = next[0]; i <= n; i = next[i]) if (!con[i] && !vis[i]) { del(i); vis[i] = 1; ans[cnt]++; q[++tail] = i; } for (R Edge *iter = last[now]; iter; iter = iter -> next) con[iter -> to] = 0; } } int main() { // setfile(); n = FastIn(), m = FastIn(); if (1ll * n * (n - 1) >> 1 == m) { printf("%d\n",n ); for (R int i = 1; i <= n; ++i) printf("1 "); return 0; } for (R int i = 0; i <= n; ++i) next[i] = i + 1; for (R int i = 1; i <= n + 1; ++i) prev[i] = i - 1; for (R int i = 1; i <= m; ++i) { R int a = FastIn(), b = FastIn(); link(a, b); } for (R int i = next[0]; i <= n; i = next[i]) if (!vis[i]) { ans[++cnt] = 1; floodfill(i); } printf("%d\n",cnt ); std::sort(ans + 1, ans + cnt + 1); for (R int i = 1; i <= cnt; ++i) printf("%d ",ans[i] ); return 0; }