题意:给定一个图,点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的更多相关文章
-
开始做POI啦...
库 为了效率搞了这么一个库: 现在版本号1.14(一月十四日更新版本囧..) http://pan.baidu.com/s/1c0SoGfu [source] http://pan.baidu.com ...
-
BZOJ1098: [POI2007]办公楼biu
从问题可以看出是求补图的连通块及点数 但补图太大.所以考虑缩小规模. 当一个点归属于一个连通块后,它以后就不需要了.所以可以用链表,删去这个点,也就减小了规模. 一个点开始bfs,每个点只会进队一次, ...
-
bzoj 1098 [POI2007]办公楼biu bfs+补图+双向链表
[POI2007]办公楼biu Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 1543 Solved: 743[Submit][Status][Di ...
-
5098: [BZOJ1098][POI2007]办公楼biu
5098: [BZOJ1098][POI2007]办公楼biu 没有数据结构就很棒 一个看上去非常玄学的代码 const int N=1e5+10,M=2e6+10; int n,m; int fa[ ...
-
【BZOJ】1098: [POI2007]办公楼biu(补图+bfs+链表)
http://www.lydsy.com/JudgeOnline/problem.php?id=1098 显然答案是补图连通块..... 想到用并查集...可是连补图的边都已经...n^2了...怎么 ...
-
[BZOJ 1098] [POI2007] 办公楼biu 【链表优化BFS】
题目链接:BZOJ - 1098 题目分析 只有两个点之间有边的时候它们才能在不同的楼内,那么就是说如果两个点之间没有边它们就一定在同一座楼内. 那么要求的就是求原图的补图的连通块. 然而原图的补图的 ...
-
【链表】Bzoj1098[POI2007]办公楼biu
Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决 ...
-
【刷题】BZOJ 1098 [POI2007]办公楼biu
Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的 电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD ...
-
【BZOJ1098】[POI2007]办公楼biu
题目一开始看以为和强联通分量有关,后来发现是无向边,其实就是求原图的补图的联通块个数和大小.学习了黄学长的代码,利用链表来优化,其实就是枚举每一个人,然后把和他不相连的人都删去放进同一个联通块里,利用 ...
随机推荐
-
【BZOJ-1670】Building the Moat护城河的挖掘 Graham扫描法 + 凸包
1670: [Usaco2006 Oct]Building the Moat护城河的挖掘 Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 464 Solv ...
-
iOS富文本的使用
NSString *name = nil; if (_payNumber == 1) { name = [NSString stringWithFormat:@"向%@收款",na ...
-
sprint3 总结
sprint3 本次的主要任务是找项目中的bug,并与客户不断地沟通以满足客户的要求.队友主要负责找项目中的bug或提出一些建议.我主要是负责与客户沟通和修复bug.总的来说进展还算顺利. 团队贡献分 ...
-
Java:Comparator接口
public interface Comparator<T> 接口里面的方法 int compare(T o1, T o2) o1 > o2 返回 1 o1 = o2 返回 0 o1 ...
-
docker - 设置HTTP/HTTPS 代理
背景 将docker的服务器环境切换到新的网络之后,由于服务器的internet是受限制的(需要连接配置远程代理,不能直接上网).因此,在使用docker连接docker hub 的时候,就会出错: ...
-
box-sizing position
box-sizing 属性 用于更改用于计算元素宽度和高度的默认的 CSS 盒子模型.可以使用此属性来模拟不正确支持CSS盒子模型规范的浏览器的行为. /* 关键字 值 */ box-sizing: ...
-
CentOS 7下使用Gitolite搭建Git私服
1. 搭建环境 CentOS7, git version 1.8.3.1 2. 安装依赖包 yum install curl-devel expat-devel gettext-devel opens ...
-
jq动画分析1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
-
使用子查询创建表(oracle)
转自:https://blog.csdn.net/lxh123456789asd/article/details/81164321 语句: CREATE TABLE tablename[(column ...
-
C#字符串截取、获取当前电脑时间、判断输入日期对错 随手记
字符串截取:这个就当复习了,看意见就可以 //身份证生日截取 //Console.WriteLine("请输入18位身份证号:"); //string x = Console.Re ...