題意:給定一個圖,點n<=105,邊m<=106,如今求它的補圖有多少個聯通份量。。node
思路:很容易想到並查集,可是補圖邊太多了。。ios
因而只能優化掉一些多餘的邊。。ide
具體作法是用隊列優化。。優化
剛開始把全部沒被鏈接的點用一個鏈表鏈接起來,那麼選取一個未擴展得點u,就能夠吧鏈表分紅兩個,一個就是跟他補圖有邊的,一個是沒邊的。。spa
並把有邊的跟他鏈接起來。。刪除鏈表。。並放入隊列。。code
這樣每一個點進入隊列一次,每條邊被訪問2次。。時間複雜度爲O(n+m)blog
code:隊列
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<set> 10 #include<vector> 11 #include<queue> 12 #include<stack> 13 #include<ctime> 14 #define repf(i, a, b) for (int i = (a); i <= (b); ++i) 15 #define repd(i, a, b) for (int i = (a); i >= (b); --i) 16 #define M0(x) memset(x, 0, sizeof(x)) 17 #define Inf 0x7fffffff 18 #define MP make_pair 19 #define PB push_back 20 #define eps 1e-8 21 #define pi acos(-1.0) 22 using namespace std; 23 const int maxn = 120000; 24 const int maxm = 4200000; 25 struct edge{ 26 int v, next; 27 } e[maxm]; 28 struct node{ 29 node *x, *y; 30 } n1[maxn], n2[maxn], *list[2], *d[2], tr, *null = &tr; 31 int fa[maxn], last[maxn], tot, n, m; 32 33 void add(const int& u, const int& v){ 34 e[tot] = (edge){v, last[u]}, last[u] = tot++; 35 } 36 37 void init(){ 38 memset(last, -1, sizeof(last)); 39 int u, v; 40 for (int i = 0; i < m; ++i){ 41 scanf("%d%d", &u, &v); 42 add(u, v), add(v, u); 43 } 44 } 45 46 int sz[maxn], inlist[maxn]; 47 int find(int k){ 48 return fa[k] == k ? k : fa[k] = find(fa[k]); 49 } 50 51 void delnode(node *it){ 52 it->x->y = it->y, it->y->x = it->x; 53 it->x = it->y = null; 54 } 55 56 void addnode(node *list, node *it){ 57 it->x = list, it->y = list->y; 58 list->y->x = it, list->y = it; 59 } 60 61 void clear(int c){ 62 node *uu; 63 for (node *it = list[c]; it != null;){ 64 uu = it->y; 65 it->x = it->y = null; 66 it = uu; 67 } 68 } 69 70 void solve(){ 71 M0(n1), M0(n2), M0(inlist); 72 list[0] = n1 + n + 1, list[1] = n2 + n + 1; 73 node *it, *uu; 74 list[0]->x = list[0]->y = null, list[1]->x = list[1]->y = null; 75 d[0] = n1, d[1] = n2; 76 int c = 0, u, v; 77 for (int i = 1; i <= n; ++i) addnode(list[c], d[c] + i), inlist[i] = 1; 78 for (int i = 1; i <= n; ++i) fa[i] = i; 79 queue<int> q; 80 while (list[c]->y != null){ 81 u = list[c]->y - d[c]; 82 q.push(u); 83 while (!q.empty()){ 84 int s = c ^ 1; 85 u = q.front(), q.pop(); 86 clear(s); 87 for (int p = last[u]; ~p; p = e[p].next){ 88 v = e[p].v; 89 if (!inlist[v]) continue; 90 delnode(d[c] + v); 91 addnode(list[s], d[s] + v); 92 } 93 int fu = find(u), fv; 94 for (it = list[c]->y; it != null; it = it->y){ 95 v = it - d[c]; 96 if (!inlist[v]) continue; 97 fv = find(v); 98 if (fu != fv) fa[fv] = fu; 99 inlist[v] = 0, q.push(v); 100 } 101 c = s; 102 } 103 } 104 M0(sz); 105 for (int i = 1; i <= n; ++i) 106 ++sz[find(i)]; 107 vector<int> ans; 108 for (int i = 1; i <= n; ++i) if (sz[i]) 109 ans.push_back(sz[i]); 110 sort(ans.begin(), ans.end()); 111 printf("%d\n", (int)ans.size()); 112 for (int i = 0; i < (int)ans.size(); ++i) 113 i == ans.size()-1 ? printf("%d\n", ans[i]) : printf("%d ", ans[i]); 114 115 } 116 117 int main(){ 118 // freopen("a.in", "r", stdin); 119 // freopen("a.out", "w", stdout); 120 while (scanf("%d%d", &n, &m) != EOF){ 121 init(); 122 solve(); 123 } 124 return 0; 125 }