卧薪尝胆,厚积薄发。
POI2007 BIU-Offices
Date: Wed Oct 17 09:58:54 CST 2018 In Category: NoCategory

Description:

给出一个图,把此图分成尽可能多的集合,满足任意不在同一集合的点之间都有边相连。
$1\leqslant n\leqslant 10^5,1\leqslant m\leqslant 2\times 10^6$

Solution:

答案就是反图的联通块数,但建边是 $O(n^2)$ 的。
求联通块数主要有两种方法, $BFS$ 和并查集,这里题解给出了一个链表优化 $BFS$ 的做法,大概就是先把所有点加进链表中,作为反图上还没有访问过的点,然后取出来一个,遍历他的所有出边,如果访问过就跳过,否则把他从链表中删除并加进另一个临时链表中,由于我们是在反图上 $BFS$ ,所以链表中剩的点就是这次遍历到的点,把他们打上标记加进队列中,这时还没访问过的点就是临时链表中的点,把他们依次加进原链表中继续 $BFS$ 即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;
inline int read()
{
register int res = 0,f = 1;
register char c = getchar();
while(!isdigit(c))
{
if(c == '-')f = -1;
c = getchar();
}
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res * f;
}
int n,m;
#define MAXN 100010
#define MAXM 2000010
struct edge
{
int to,nxt;
}e[MAXM << 1];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
++edgenum;e[edgenum].to = a;e[edgenum].nxt = lin[b];lin[b] = edgenum;
return;
}
struct node
{
node *l,*r;
int v;
};
struct list
{
node l[MAXN],h,t;
node *head,*tail;
int siz;
list()
{
siz = 0;
head = &h;tail = &t;
head -> r = tail;tail -> l = head;
head -> l = NULL;tail -> r = NULL;
}
void init()
{
siz = 0;
head -> r = tail;tail -> l = head;
head -> l = NULL;tail -> r = NULL;
return;
}
void insert(int k)
{
++siz;
node* t = &l[k];t -> v = k;
t -> l = head;t -> r = head -> r;
t -> r -> l = t;head -> r = t;
return;
}
void remove(int k)
{
--siz;
node *t = &l[k];
t -> l -> r = t -> r;
t -> r -> l = t -> l;
return;
}
int get()
{
return head -> r -> v;
}
}l[2];
bool v[MAXN];
int siz[MAXN];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)l[0].insert(i);
for(int i = 1;i <= m;++i)add(read(),read());
memset(v,false,sizeof(v));
int cnt = 0;
while(l[0].siz != 0)
{
++cnt;
int s = l[0].get();l[0].remove(s);
queue<int> q;q.push(s);v[s] = true;
siz[cnt] = 0;
while(!q.empty())
{
int k = q.front();q.pop();
++siz[cnt];
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(!v[e[i].to])
{
l[1].insert(e[i].to);
l[0].remove(e[i].to);
}
}
for(node *i = l[0].head -> r;i != l[0].tail;i = i -> r)
{
if(!v[i -> v])
{
q.push(i -> v);
v[i -> v] = true;
}
}
l[0].init();
for(node *i = l[1].head -> r;i != l[1].tail;i = i -> r)
{
if(!v[i -> v])l[0].insert(i -> v);
}
l[1].init();
}
}
cout << cnt << endl;
sort(siz + 1,siz + 1 + cnt);
for(int i = 1;i <= cnt;++i)
{
printf("%d ",siz[i]);
}
puts("");
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡