题意:给定一个图,点n<=105,边m<=106,现在求它的补图有多少个联通分量。。

思路:很容易想到并查集,但是补图边太多了。。

于是只能优化掉一些多余的边。。

具体做法是用队列优化。。

刚开始把所有没被连接的点用一个链表连接起来,那么选取一个未扩展得点u,就可以吧链表分成两个,一个就是跟他补图有边的,一个是没边的。。

并把有边的跟他连接起来。。删除链表。。并放入队列。。

这样每个点进入队列一次,每条边被访问2次。。时间复杂度为O(n+m)

code:

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<ctime>
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define M0(x) memset(x, 0, sizeof(x))
#define Inf 0x7fffffff
#define MP make_pair
#define PB push_back
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
const int maxn = ;
const int maxm = ;
struct edge{
int v, next;
} e[maxm];
struct node{
node *x, *y;
} n1[maxn], n2[maxn], *list[], *d[], tr, *null = &tr;
int fa[maxn], last[maxn], tot, n, m; void add(const int& u, const int& v){
e[tot] = (edge){v, last[u]}, last[u] = tot++;
} void init(){
memset(last, -, sizeof(last));
int u, v;
for (int i = ; i < m; ++i){
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
}
} int sz[maxn], inlist[maxn];
int find(int k){
return fa[k] == k ? k : fa[k] = find(fa[k]);
} void delnode(node *it){
it->x->y = it->y, it->y->x = it->x;
it->x = it->y = null;
} void addnode(node *list, node *it){
it->x = list, it->y = list->y;
list->y->x = it, list->y = it;
} void clear(int c){
node *uu;
for (node *it = list[c]; it != null;){
uu = it->y;
it->x = it->y = null;
it = uu;
}
} void solve(){
M0(n1), M0(n2), M0(inlist);
list[] = n1 + n + , list[] = n2 + n + ;
node *it, *uu;
list[]->x = list[]->y = null, list[]->x = list[]->y = null;
d[] = n1, d[] = n2;
int c = , u, v;
for (int i = ; i <= n; ++i) addnode(list[c], d[c] + i), inlist[i] = ;
for (int i = ; i <= n; ++i) fa[i] = i;
queue<int> q;
while (list[c]->y != null){
u = list[c]->y - d[c];
q.push(u);
while (!q.empty()){
int s = c ^ ;
u = q.front(), q.pop();
clear(s);
for (int p = last[u]; ~p; p = e[p].next){
v = e[p].v;
if (!inlist[v]) continue;
delnode(d[c] + v);
addnode(list[s], d[s] + v);
}
int fu = find(u), fv;
for (it = list[c]->y; it != null; it = it->y){
v = it - d[c];
if (!inlist[v]) continue;
fv = find(v);
if (fu != fv) fa[fv] = fu;
inlist[v] = , q.push(v);
}
c = s;
}
}
M0(sz);
for (int i = ; i <= n; ++i)
++sz[find(i)];
vector<int> ans;
for (int i = ; i <= n; ++i) if (sz[i])
ans.push_back(sz[i]);
sort(ans.begin(), ans.end());
printf("%d\n", (int)ans.size());
for (int i = ; i < (int)ans.size(); ++i)
i == ans.size()- ? printf("%d\n", ans[i]) : printf("%d ", ans[i]); } int main(){
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
while (scanf("%d%d", &n, &m) != EOF){
init();
solve();
}
return ;
}

[poi2007] biu的更多相关文章

  1. 开始做POI啦...

    库 为了效率搞了这么一个库: 现在版本号1.14(一月十四日更新版本囧..) http://pan.baidu.com/s/1c0SoGfu [source] http://pan.baidu.com ...

  2. BZOJ1098: [POI2007]办公楼biu

    从问题可以看出是求补图的连通块及点数 但补图太大.所以考虑缩小规模. 当一个点归属于一个连通块后,它以后就不需要了.所以可以用链表,删去这个点,也就减小了规模. 一个点开始bfs,每个点只会进队一次, ...

  3. bzoj 1098 [POI2007]办公楼biu bfs+补图+双向链表

    [POI2007]办公楼biu Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1543  Solved: 743[Submit][Status][Di ...

  4. 5098: [BZOJ1098][POI2007]办公楼biu

    5098: [BZOJ1098][POI2007]办公楼biu 没有数据结构就很棒 一个看上去非常玄学的代码 const int N=1e5+10,M=2e6+10; int n,m; int fa[ ...

  5. 【BZOJ】1098: [POI2007]办公楼biu(补图+bfs+链表)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1098 显然答案是补图连通块..... 想到用并查集...可是连补图的边都已经...n^2了...怎么 ...

  6. [BZOJ 1098] [POI2007] 办公楼biu 【链表优化BFS】

    题目链接:BZOJ - 1098 题目分析 只有两个点之间有边的时候它们才能在不同的楼内,那么就是说如果两个点之间没有边它们就一定在同一座楼内. 那么要求的就是求原图的补图的连通块. 然而原图的补图的 ...

  7. 【链表】Bzoj1098[POI2007]办公楼biu

    Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决 ...

  8. 【刷题】BZOJ 1098 [POI2007]办公楼biu

    Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的 电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD ...

  9. 【BZOJ1098】[POI2007]办公楼biu

    题目一开始看以为和强联通分量有关,后来发现是无向边,其实就是求原图的补图的联通块个数和大小.学习了黄学长的代码,利用链表来优化,其实就是枚举每一个人,然后把和他不相连的人都删去放进同一个联通块里,利用 ...

随机推荐

  1. VueJS取得URL参数

    vuejs取得URL中参数的值 地址:http://localhost:3333/#/index?id=001 结果:001 console.log(this.$route.query.id)

  2. JavaScript基础认知

    此文只适用于初学者,大神们就不要看了,嘿嘿~ 一.定义变量 关键字 var,由此关键字定义变量,例如:var a =21:就把21这个数定义给了变量a 二.基本数据类型 1.Number类型 表示数字 ...

  3. Hibernate一对多(注解)

    <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hi ...

  4. 使用 Sandcastle 生成代码帮助文档

    使用 Sandcastle可以生成MSDN风格的帮助文档,生成的帮助文档既可以是chm文档,也可以是MS Help 2.x帮助文档. 1 下载并安装Sandcastle Sandcastle下载地址为 ...

  5. Android之ImageSwitcher

    要点: (查看Api总结) 1:ImageSwitcher 继承 ViewSwitcher, (ViewSwitcher 有继承FrameLayout ) 2: 要实现切图必须实现 ViewSwitc ...

  6. MySQL pdo预处理能防止sql注入的原因

    MySQL pdo预处理能防止sql注入的原因: 1.先看预处理的语法 $pdo->prepare('select * from biao1 where id=:id'); $pdo->e ...

  7. iOS随机页面NSClassFromString

      NSString *className = self.classNameArray[randomNumber]; Class viewClass = NSClassFromString(class ...

  8. base64/62 加解密的实现。

    base64/62加解密代码下载地址: http://files.cnblogs.com/files/Kingfans/base64(62)加解密.zip base64: base62:

  9. vue2 上传图片

    <template> <div class="vue-upload-img-multiple"> <div v-if="images.len ...

  10. centos 如何清理/dev/vda1系统盘

    df-h检查一台服务器磁盘使用空间,发现磁盘已经使用了100% 思路是: 1.cd /usr 2.du -sh * 看哪个目录占用空间大 3.重复前两步,根据实际情况删除或者移走 4.日志的话可以运行 ...