[poi2007] biu
题意:给定一个图,点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
题目一开始看以为和强联通分量有关,后来发现是无向边,其实就是求原图的补图的联通块个数和大小.学习了黄学长的代码,利用链表来优化,其实就是枚举每一个人,然后把和他不相连的人都删去放进同一个联通块里,利用 ...
随机推荐
- Java 的replace和replaceAll的使用
(1)replace() 方法通过用 newChar 字符替换字符串中出现的所有 oldChar 字符,并返回替换后的新字符串. public String replace(char oldChar, ...
- LINUX 更新
sudo apt-get dist-upgrade,更新所有的软件
- 快捷键的记录,Word和PPT的一些常用操作
1)PPT背景设置:右键->背景->背景填充下的下拉箭头->填充效果->图片- >选择图片->确定->选择应用或应用全部 2)Word,PPT求和符号怎么打 ...
- 問題排查:DataGridView 資料行下拉選單,資料繫結階段顯示 DataGridViewComboBoxCell 值無效
可能原因: 1.下拉選單的選項資料繫結晚於 DataGridView 的資料繫結 2.下拉選單的 DataPropertyName 屬性,比 DisplayMember.ValueMember 早賦值 ...
- MySQL数据库设置远程访问权限方法总结
1,设置访问单个数据库权限 mysql>grant all privileges on test.* to 'root'@'%'; 说明:设置用户名为root,密码为空,可访问数据库test 2 ...
- ReferenceQueue<T>随笔
参考资料: ReferenceQueue食用手册 java引用食用手册 ReferenceQueue源代码里面很好的展示了java队列的实现思路, 以及多线程观察者的实现思路 多线程观察者实现思路: ...
- RHEL7学习之NTP配置
一,安装NTP [root@localhost ~]# yum install ntp Loaded plugins: product-id, subscription-manager This sy ...
- DEV GridControl双击行事件
首先,需要将gridview1.OptionsBehavior.Editable设为false //双击行弹出nodeDetail信息 private void gridView1_MouseDown ...
- DataTable 和Json 字符串互转
#region DataTable 转换为Json字符串实例方法 /// <summary> /// GetClassTypeJosn 的摘要说明 /// </summary> ...
- jsp页面输入小写金额转大写
<script> function chineseNumber(num){ if (isNaN(num) || num > Math.pow(10, 12)) return &quo ...