题意:给定一个图,点n<=105,边m<=106,现在求它的补图有多少个联通分量。。
思路:很容易想到并查集,但是补图边太多了。。
于是只能优化掉一些多余的边。。
具体做法是用队列优化。。
刚开始把所有没被连接的点用一个链表连接起来,那么选取一个未扩展得点u,就可以吧链表分成两个,一个就是跟他补图有边的,一个是没边的。。
并把有边的跟他连接起来。。删除链表。。并放入队列。。
这样每个点进入队列一次,每条边被访问2次。。时间复杂度为O(n+m)
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 ", (int)ans.size()); 112 for (int i = 0; i < (int)ans.size(); ++i) 113 i == ans.size()-1 ? printf("%d ", 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 }