</pre><p><span style="white-space:pre"> </span><span style="font-size:24px;">BZOJ1098</span></p><pre><span style="font-family:Microsoft YaHei;">题意:先转为补图,然后求联通块的个数。
</span><span style="font-family:Microsoft YaHei;">思路:
</span><span style="font-family:Microsoft YaHei;"><span style="white-space:pre"> </span>1.可以证明答案是O(N^1/2)级别的,因为首先对于一定的M,若答案最大则每个联通块必为点,即答案为M^1/2(假设N个点,每个点必然要和其它N-1个点连线,若N再增加,则每个点平均出度不足)。
</span><span style="font-family:Microsoft YaHei;"><span style="white-space:pre"> </span>2.直接转化为补图是不现实的,即一次性求出答案是不现实的,提示我们按一个一个加点的顺序做。
</span><span style="font-family:Microsoft YaHei;">解法:
</span><span style="font-family:Microsoft YaHei;"><span style="white-space:pre"> </span>使用并查集,对于每个点,统计和已经统计过的所有联通块内点的联通情况,若点i与联通块内某个点无连边,则i和该联通块合并。具体实现我用了循环队列。。。
</span><span style="font-family:Microsoft YaHei;"><span style="white-space:pre"> </span>另外,复杂度的话应该是O(N*α+N*M^1/2)</span>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100010, maxm = 4000010;
int m0 = 0, first[maxn], next[maxm], to[maxm], fa[maxn], cnt[maxn], vis[maxn];
int q[maxn], front=1, rear=2;
int n, m, Ans = 0, Anscnt[maxn], viscnt, vispos[maxn];
int getfa(int x)
{
if (fa[x] != x)
return fa[x] = getfa(fa[x]);
else
return x;
}
void addedge(int u, int v)
{
m0++; next[m0] = first[u]; first[u] = m0; to[m0] = v;
}
void add(int &i)
{
if (i == 100005)i = 1;
else i++;
}
int main()
{
int u, v;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
{
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
}
cnt[1] = 1;
fa[1] = 1;
q[1] = 1;
int newrear;
for (int i = 2; i <= n; i++)
{
cnt[i] = 1;
fa[i] = i;
viscnt = 0;
for (int e = first[i]; e; e = next[e])
if(fa[to[e]])
{
vispos[++viscnt] = getfa(to[e]);
vis[vispos[viscnt]]++;
}
newrear = rear;
for (int j = front; j != rear; add(j))
{
front = j;
if (cnt[q[j]] != vis[q[j]])
{
cnt[i] += cnt[q[j]];
cnt[q[j]] = 0;
fa[q[j]] = i;
}
else
{
q[newrear] = q[j];
add(newrear);
}
}
add(front);
q[newrear] = i;
add(newrear);
for (int j = 1; j <= viscnt; j++)
vis[vispos[j]] = 0;
rear = newrear;
}
for (int j = front; j != rear; add(j))
{
Ans++;
Anscnt[Ans] = cnt[q[j]];
}
sort(Anscnt + 1,Anscnt + Ans + 1);
printf("%d\n", Ans);
for (int i = 1; i <= Ans; i++)
printf("%d ", Anscnt[i]);
return 0;
}