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

这种题出到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 <bits/stdc++.h>
#define N 300000
using namespace std; vector <int> 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 = ; 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 + ;
for (int p = t; p; p = nx[p]) vis[p] = ;
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]] = ;
if (!solve2(tt[i])) return ;
}
return ;
}
set <int> S[N];
int test(int a, int b)
{
return S[a].count(b);
}
int solve2(int t)
{
if (nx[t] == ) return ;
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] = ; 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 = ;
for (int b = q; b; b = nx[b])
if (!test(a, b))
{
bo = ;
goto haha;
}
haha:
if (bo)
{
nx[nl[p]] = q;
nl[p] = nl[q];
nl[q] = ; ne[c] = ne[q];
ne[q] = ;
q = ne[c];
}
else
{
c = ne[c];
q = ne[q];
}
}
}
}
if (ne[t] == ) return ;
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 = ; 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 <int> nls;
for (int p = t; p; p = ne[p]) nls.push_back(p);
for (int p = ; p < nls.size(); ++ p)
if (!solve1(nls[p])) return ;
return ;
}
int main()
{
//freopen("C.in", "r", stdin);
scanf("%d", &T);
while (T --)
{
scanf("%d%d", &n, &m);
for (int i = ; 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 = ; i < n; ++ i) nx[i] = i + , ne[i] = ;
nx[n] = ;
if (solve1()) puts("TAK"); else puts("NIE"); for (int i = ; i <= n; ++ i) bi[i].clear(), S[i].clear();
}
}

bzoj 2075: [POI2004]KAG的更多相关文章

  1. BZOJ 2073: [POI2004]PRZ( 状压dp )

    早上这道题没调完就去玩NOI网络同步赛了.... 状压dp , dp( s ) 表示 s 状态下所用的最短时间 , 转移就直接暴力枚举子集 . 可以先预处理出每个状态下的重量和时间的信息 . 复杂度是 ...

  2. bzoj 2073: [POI2004]PRZ

    2073: [POI2004]PRZ Description 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍在桥上的 ...

  3. Bzoj: 2073 [POI2004]PRZ 题解

    2073: [POI2004]PRZ Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 401  Solved: 296[Submit][Status][D ...

  4. BZOJ 2073: [POI2004]PRZ [DP 状压]

    传送门 水题不解释 这道题的主要目的在于记录一个枚举子集的技巧 #include <iostream> #include <cstdio> #include <cstri ...

  5. BZOJ 2069: [POI2004]ZAW(Dijkstra + 二进制拆分)

    题意 给定一个有 \(N\) 个点 \(M\) 条边的无向图, 每条无向边 最多只能经过一次 . 对于边 \((u, v)\) , 从 \(u\) 到 \(v\) 的代价为 \(a\) , 从 \(v ...

  6. 【刷题】BZOJ 2069 [POI2004]ZAW

    Description 在Byte山的山脚下有一个洞穴入口. 这个洞穴由复杂的洞室经过隧道连接构成. 洞穴的入口是一条笔直通向"前面洞口"的道路. 隧道互相都不交叉(他们只在洞室相 ...

  7. BZOJ.2069.[POI2004]ZAW(最短路Dijkstra 按位划分)

    题目链接 \(Description\) 给定一张带权图(边是双向的,但不同方向长度不同).求从1出发,至少经过除1外的一个点,再回到1的最短路.点和边不能重复经过. \(n\leq5000,m\le ...

  8. BZOJ 2073 [POI2004]PRZ(状压DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2073 [题目大意] 任何时候队伍在桥上的人都不能超过一定的限制. 所以这只队伍过桥时只 ...

  9. bzoj 2096 [POI2004]ZAW——二进制枚举

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2069 可以把直接相连的点分成  从1点出的一部分  和  走向1点的一部分.多起点最短路就和 ...

随机推荐

  1. Android 获取网络链接类型

    /** * 获取当前网络类型 * @return 0:没有网络 1:WIFI网络 2:WAP网络 3:NET网络 */ public int getNetworkType() { int netTyp ...

  2. hdu 1860 统计字符

    Problem Description 统计一个给定字符串中指定的字符出现的次数 Input 测试输入包含若干测试用例,每个测试用例包含2行,第1行为一个长度不超过5的字符串,第2行为一个长度不超过8 ...

  3. 理解JavaScript中的事件处理 阻止冒泡event.stopPropagation();

    原文地址:http://www.cnblogs.com/binyong/articles/1750263.html 这篇文章对于了解Javascript的事件处理机制非常好,将它全文转载于此,以备不时 ...

  4. Linux 之 rsyslog 系统日志转发(转载)

    一.rsyslog 介绍 ryslog 是一个快速处理收集系统日志的程序,提供了高性能.安全功能和模块化设计.rsyslog 是syslog 的升级版,它将多种来源输入输出转换结果到目的地,据官网介绍 ...

  5. double精度的坑与BigDecimal

    近期经常接触支付相关的功能,在开发及测试过程中,开始金额都使用的是double类型,而近期新进的需求存在支付时打折的情况,也就是会出现如 1.23元的情况,那么这时候问题来了,如果是直接使用1.23进 ...

  6. Javascript:DOM表格操作

    需求说明: /* *需求说明: *获取元素:tBodies,tHead,tFoot,rows,cells *表格的创建 *数据添加 *隔行变色 *删除操作,剩余表格重新计算,实现隔行变色 */ HTM ...

  7. Java Web的数据库操作(一)

    一.JDBC技术 1.JDBC简介 JDBC是Java程序与数据库系统通信的标准API,它定义在JDK的API中,通过JDBC技术,Java程序可以非常方便地与各种数据库交互,JDBC在Java程序与 ...

  8. jQuery mouseover,mouseout事件多次执行的问题处理

    控制鼠标移上移下事件,在使用Jquery 的mouseover,mouseout事件时,元素内部含有其它元素,会造成该事件多次的触发的情况. 问题解析 在用到mouseover和mouseout事件来 ...

  9. 一小时搞定DIV+CSS布局-固定页面开度布局

    本文讲解使用DIV+CSS布局最基本的内容,读完本文你讲会使用DIV+CSS进行简单的页面布局. 转载请标明:http://www.kwstu.com/ArticleView/divcss_20139 ...

  10. css实现ie6以上文字高度未知垂直居中

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...