博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj 2075: [POI2004]KAG
阅读量:4543 次
发布时间:2019-06-08

本文共 3858 字,大约阅读时间需要 12 分钟。

整天鬼畜题搞搞,感觉药丸……

这种题出到xjoi模拟题里,太神了……

 

这题的核心在于分割Cograph,尝试把Cograph的合成过程给求出来。

 

我们将这张图中的边定为黑边,在这张图的补图中出现的边定为白边,则黑边和白边构成了一个完全图。

1.如果当前这张图的黑边是不联通的,那么可以检查所有的黑边构成的联通块是不是Cograph,如果都是Cograph,则原图也为Cograph

2.如果当前这张图的白边是不联通的,那么可以检查所有的白边构成的联通块是不是Cograph,如果都是Cograph,则原图也为Cograph

 

3.如果当前这张图中的白边黑边都是联通的,直接返回该图不是Cograph

 

这样做显然是正确的,但是时间复杂度太高了,每次划分的复杂度是\(O(m)\)的,由于白边有\(O(n^2)\)条,因此这个做法也是\(O(n^2)\)

 

显然是会爆炸的……

考虑优化这个做法,我们并不需要枚举所有白边,当找到一条白边时,就将它所连接的两个白联通块合并,合并次数是\(O(n)\)的

因此需要一种支持快速 合并联通块、查询一个联通块到另一个联通块之间所有边的数据结构……

 

这里用链表维护联通块……(为什么不用并查集?因为我要访问该联通块所有的点

 

这样就可以保证每次查询的边一定是不在当前同一个联通块中,

查询的两个点间要么是黑边要么是白边,黑边只有\(O(m)\)条,由于只有\(O(n)\)次合并,因此扫到的白边只有\(O(n)\)条,时间复杂度是\(O(n + m)\)的

 

这样对于一个问题,只需要\(O(n + m)\)就可以把它变成若干个小原问题了。

 

由于Cograph每层的分割至少有\(O(n)\)条连接在白联通块之间的黑边被删除了,因此这样分割的层数是\(O(min(m / n, n))\)的

 

总时间复杂度\(O((n + m)\sqrt{m})\)

跑的稍微有点慢啊~

#include 
#define N 300000using namespace std; vector
bi[N], bn[N];int T, n, m;int ai[N];int nx[N], ne[N], nl[N], tot;int vis[N], td[N], tt[N], col[N];int tmp;void dfs1(int t, int c){ vis[t] = c; for (int i = 0; i < bi[t].size(); ++ i) if (!vis[bi[t][i]]) dfs1(bi[t][i], c);}int solve2(int t);int solve1(int t){ int nw = tmp + 1; for (int p = t; p; p = nx[p]) vis[p] = 0; for (int p = t; p; p = nx[p]) if (!vis[p]) dfs1(p, vis[p] = ++ tmp); for (int p = t; p; p = nx[p]) { if (!tt[vis[p]]) tt[vis[p]] = td[vis[p]] = p; else { nx[td[vis[p]]] = p; td[vis[p]] = p; } } for (int i = nw; i <= tmp; ++ i) { nx[td[i]] = 0; if (!solve2(tt[i])) return 0; } return 1;}set
S[N];int test(int a, int b){ return S[a].count(b);}int solve2(int t){ if (nx[t] == 0) return 1; for (int p = t; p; p = nx[p]) ne[p] = nx[p], nl[p] = p; for (int p = t; p; p = ne[p]) nx[p] = 0; for (int p = t; p; p = ne[p]) { for (int a = p; a; a = nx[a]) { for (int q = ne[p], c = p; q; ) { int bo = 0; for (int b = q; b; b = nx[b]) if (!test(a, b)) { bo = 1; goto haha; } haha: if (bo) { nx[nl[p]] = q; nl[p] = nl[q]; nl[q] = 0; ne[c] = ne[q]; ne[q] = 0; q = ne[c]; } else { c = ne[c]; q = ne[q]; } } } } if (ne[t] == 0) return 0; for (int p = t; p; p = ne[p]) for (int q = p; q; q = nx[q]) col[q] = p, bn[q].clear(); for (int p = t; p; p = ne[p]) for (int q = p; q; q = nx[q]) for (int a = 0; a < bi[q].size(); ++ a) if (col[bi[q][a]] == col[q]) bn[q].push_back(bi[q][a]); for (int p = t; p; p = ne[p]) for (int q = p; q; q = nx[q]) bi[q] = bn[q]; vector
nls; for (int p = t; p; p = ne[p]) nls.push_back(p); for (int p = 0; p < nls.size(); ++ p) if (!solve1(nls[p])) return 0; return 1;}int main(){ //freopen("C.in", "r", stdin); scanf("%d", &T); while (T --) { scanf("%d%d", &n, &m); for (int i = 1; i <= m; ++ i) { int a, b; scanf("%d%d", &a, &b); bi[a].push_back(b); S[a].insert(b); bi[b].push_back(a); S[b].insert(a); } for (int i = 1; i < n; ++ i) nx[i] = i + 1, ne[i] = 0; nx[n] = 0; if (solve1(1)) puts("TAK"); else puts("NIE"); for (int i = 1; i <= n; ++ i) bi[i].clear(), S[i].clear(); }}

 

转载于:https://www.cnblogs.com/AwD-/p/6266351.html

你可能感兴趣的文章
git基础(2)
查看>>
Struts2 拦截器的第一次
查看>>
java的局部变量和成员变量以及区别
查看>>
app测试小结20170216
查看>>
41. First Missing Positive
查看>>
Java异常处理
查看>>
php连接数据库 搜索数据形成数组,转为字符串
查看>>
ORACLE——EXTRACT() 截取日期时间的函数使用
查看>>
sgu 102 Coprimes
查看>>
[读书笔记]C#学习笔记四: C#2.0泛型 可控类型 匿名方法和迭代器
查看>>
ASP.NET页面周期学习笔记之一
查看>>
spark-sql cli 参数 及使用
查看>>
hdu 1312 Red and Black
查看>>
matlab 人面检测
查看>>
推荐jade、sass、artTemplate方式书写
查看>>
一个“雷电”游戏的雏形
查看>>
时间戳转时间
查看>>
虚拟主机发布ASP.NET网站过程解析
查看>>
bzoj4784: [Zjoi2017]仙人掌
查看>>
浅谈JSP中forward和redirect
查看>>