bzoj 1098
对于关系,看其是否是“等价关系”,即满足:自反,传递,对称。
如果是可以用并查集来连接等价类。
这道题是求原图补集的联通快个数,考虑原图度最少的点(由鸽巢原理,最多为2*e/n个)。
先将未与其连边的点并在一个集合中,然后再用剩下的点暴力,每次O(n),最多暴力O(2*e/n)次,所以总的复杂度是O(e)的。
1 /************************************************************** 2 Problem: 1098 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:8932 ms 7 Memory:31140 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <vector> 13 #include <algorithm> 14 #define maxn 100010 15 using namespace std; 16 17 int n, m; 18 int dgr[maxn]; 19 vector<int> g[maxn], stk; 20 int fa[maxn], sz[maxn]; 21 bool mark[maxn]; 22 23 24 void init() { 25 for( int i=1; i<=n; i++ ) fa[i]=i; 26 } 27 int find( int a ) { 28 return a==fa[a] ? a : fa[a]=find(fa[a]); 29 } 30 void unon( int a, int b ) { 31 fa[find(a)] = find(b); 32 } 33 34 int main() { 35 scanf( "%d%d", &n, &m ); 36 for( int i=1,u,v; i<=m; i++ ) { 37 scanf( "%d%d", &u, &v ); 38 g[u].push_back( v ); 39 g[v].push_back( u ); 40 dgr[u]++, dgr[v]++; 41 } 42 int mu=1; 43 init(); 44 for( int u=2; u<=n; u++ ) if( dgr[u]<dgr[mu] ) mu=u; 45 46 for( int t=0; t<g[mu].size(); t++ ) mark[g[mu][t]]=true; 47 for( int u=1; u<=n; u++ ) if( !mark[u] ) unon(u,mu); 48 for( int t=0; t<g[mu].size(); t++ ) mark[g[mu][t]]=false; 49 50 for( int t=0; t<g[mu].size(); t++ ) stk.push_back( g[mu][t] ); 51 for( int i=0; i<stk.size(); i++ ) { 52 int u=stk[i]; 53 54 for( int t=0; t<g[u].size(); t++ ) mark[g[u][t]] = true; 55 for( int v=1; v<=n; v++ ) if( !mark[v] ) unon(u,v); 56 for( int t=0; t<g[u].size(); t++ ) mark[g[u][t]] = false; 57 } 58 for( int u=1; u<=n; u++ ) 59 sz[find(u)]++; 60 vector<int> ans; 61 for( int u=1; u<=n; u++ ) 62 if( fa[u]==u ) ans.push_back(sz[u]); 63 sort( ans.begin(), ans.end() ); 64 printf( "%d\n", ans.size() ); 65 for( int t=0; t<ans.size(); t++ ) 66 printf( "%d ", ans[t] ); 67 printf( "\n" ); 68 }