题意:给定一个图,点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. 关于android帮助文档打开慢

    打开慢的原因是:Doc目录下的html文件里含有访问google的js文件<link rel="stylesheet"href="http://fonts.goog ...

  2. C入门---位运算

    程序中的所有数在计算机内存中都是以二进制的形式储存的.位运算直接对整数在内存中的二进制位进行操作.由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快. (1),与(&)运算 ...

  3. java获取classpath

    public class PathTest { public static void main(String[] args) { //获取根路径三种方式 System.out.println(Path ...

  4. winAPI 检查系统设备拔插使用 WM_DEVICECHANGE 消息

    if(message->message == WM_DEVICECHANGE) { /*if (message->wParam == DBT_DEVICEARRIVAL || messag ...

  5. 运动 js

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. Brocade博科光纤交换机zone配置

    1.规划 交换机 端口 用途 DS6520B-A 94 存储模块1-1 95 存储模块2-1 68 DB1网卡1-1 69 DB2网卡1-1 DS6520B-B 94 存储模块1-2 95 存储模块2 ...

  7. L440 无线网卡:由于该设备有问题,Windows 已将其停止(代码 43)

    最近重装了系统,本来用的好好的,结果重启之后突然无线网卡不能用了,设备管理器老是黄色叹号!无线网卡设备状态:由于该设备有问题,Windows 已将其停止. (代码 43).      无线网卡型号:2 ...

  8. Module 'fileinfo' already loaded in Unknown on line 0

    出现的原因是:需要加载的扩展已经以而二进制文件的形式写入了php中,但是,在php.ini中却再一次动态加载 参考出处

  9. sql月份销售统计

    1.SELECT   MONTH(SellTime) as selltime,SUM(TotalPrice) as total FROM  Sell WHERE  YEAR(SellTime)=CON ...

  10. ajax select option 数据。为了下次方便信手拈来!!

    为了下次方便信手拈来!! 示例1 var form = document.forms["maddraddform"]; $(form.province).change(functi ...