这份代码可以作为找割边的模板。割边分割出来的部分是无向图的 边-双连通分量。

平面上2*n+1个点,在同一横坐标上的点之间可以任意两两匹配。同一纵坐标上的点之间也可以。问你对于所有的点i,输出i被移除之后,剩余的点能否完美匹配。

把x坐标当一列点,y坐标当一列点,原本的点当做边,建出来一个二分图。

一个连通块可以完美匹配,当且仅当其中边数为偶数。必须所有连通块的边数都是偶数,整个图才可以完美匹配。

考虑移除一个点,如果它不是割边,那么仅仅会让其所在连通块大小-1。如果其是割边,那么将其所在连通块分割成了两个连通块。就很容易在dfs的过程中统计答案。

可以做 边-双连通分量 缩点。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,K,xs[410000],ys[410000];
int e,first[410000],next[410000],v[410000],id[410000];
void AddEdge(int U,int V,int ID){
v[e]=V;
id[e]=ID;
next[e]=first[U];
first[U]=e++;
}
bool bridge[410000];
int dep,dfn[410000];
int Tarjan(int U,int te)
{
int lowU=dfn[U]=++dep;
for(int i=first[U];i!=-1;i=next[i])
if(!dfn[v[i]])
{
int lowV=Tarjan(v[i],id[i]);
lowU=min(lowU,lowV);
if(lowV>dfn[U])
bridge[i]=bridge[i^1]=1;
}
else if(id[i]!=te && dfn[v[i]]<dfn[U])
lowU=min(lowU,dfn[v[i]]);
return lowU;
}
bool vis[410000];
int cmp[410000];
bool anss[210000];
int siz[410000],cmp_sz[410000],siz2[410000];
void dfs(int U){
vis[U]=1;
cmp[U]=K;
for(int i=first[U];i!=-1;i=next[i]){
if(!vis[v[i]] && !bridge[i]){
dfs(v[i]);
}
}
}
int nows[410000];
void df1(int U){
vis[U]=1;
for(int i=first[U];i!=-1;i=next[i]){
++nows[K];
if(!vis[v[i]]){
df1(v[i]);
}
}
}
int jis;
void df2(int U){
vis[U]=1;
for(int i=first[U];i!=-1;i=next[i]){
if(!bridge[i]){
if(jis==1 && (nows[K]&1)){
anss[id[i]]=1;
}
}
if(!vis[v[i]]){
df2(v[i]);
}
}
}
void df3(int U){
vis[U]=1;
siz[U]=cmp_sz[U];
siz2[U]=1;
for(int i=first[U];i!=-1;i=next[i]){
if(!vis[v[i]]){
df3(v[i]);
siz[U]+=siz[v[i]];
siz2[U]+=siz2[v[i]];
}
}
}
void df4(int root,int U){
vis[U]=1;
for(int i=first[U];i!=-1;i=next[i]){
if(!vis[v[i]]){
if(jis==1 && (siz2[root]-1+siz[root])%2==1 &&
(siz2[v[i]]-1+siz[v[i]])%2==0 &&
(siz2[root]-siz2[v[i]]-1+siz[root]-siz[v[i]])%2==0){
anss[id[i]]=1;
}
df4(root,v[i]);
}
}
}
void df5(int U){
vis[U]=1;
for(int i=first[U];i!=-1;i=next[i]){
if(cmp[U]==cmp[v[i]]){
++cmp_sz[cmp[U]];
}
if(!vis[v[i]] && cmp[U]==cmp[v[i]]){
df5(v[i]);
}
}
}
int main(){
// freopen("b.in","r",stdin);
scanf("%d",&n);
n=n*2+1;
// n=n;
memset(first,-1,sizeof(first));
for(int i=1;i<=n;++i){
scanf("%d%d",&xs[i],&ys[i]);
AddEdge(xs[i],ys[i]+n,i);
AddEdge(ys[i]+n,xs[i],i);
}
for(int i=1;i<=n*2;++i){
if(!dfn[i]){
Tarjan(i,-1);
}
}
for(int i=1;i<=2*n;++i){
if(!vis[i]){
++K;
df1(i);
nows[K]>>=1;
if(nows[K]&1){
++jis;
}
}
}
K=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=2*n;++i){
if(!vis[i]){
++K;
df2(i);
}
}
K=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n*2;++i){
if(!vis[i]){
++K;
dfs(i);
}
}
memset(vis,0,sizeof(vis));
for(int i=1;i<=n*2;++i){
if(!vis[i]){
df5(i);
cmp_sz[cmp[i]]>>=1;
}
}
e=0;
memset(first,-1,sizeof(first));
for(int i=1;i<=n;++i){
if(cmp[xs[i]]!=cmp[ys[i]+n]){
AddEdge(cmp[xs[i]],cmp[ys[i]+n],i);
AddEdge(cmp[ys[i]+n],cmp[xs[i]],i);
}
}
jis=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=K;++i){
if(!vis[i]){
df3(i);
if((siz2[i]-1+siz[i])&1){
++jis;
}
}
}
memset(vis,0,sizeof(vis));
for(int i=1;i<=K;++i){
if(!vis[i]){
df4(i,i);
}
}
for(int i=1;i<=n;++i){
puts(anss[i] ? "OK" : "NG");
}
return 0;
}

【Tarjan算法】【DFS】Petrozavodsk Summer Training Camp 2016 Day 9: AtCoder Japanese Problems Selection, Thursday, September 1, 2016 Problem B. Point Pairs的更多相关文章

  1. 【博弈论】【SG函数】【线段树】Petrozavodsk Summer Training Camp 2016 Day 9: AtCoder Japanese Problems Selection, Thursday, September 1, 2016 Problem H. Cups and Beans

    一开始有n个杯子,每个杯子里有一些豆子,两个人轮流操作,每次只能将一个豆子移动到其所在杯子之前的某个杯子里,不过可以移动到的范围只有一段区间.问你是否先手必胜. 一个杯子里的豆子全都等价的,因为sg函 ...

  2. 【推导】【数学期望】【冒泡排序】Petrozavodsk Winter Training Camp 2018 Day 5: Grand Prix of Korea, Sunday, February 4, 2018 Problem C. Earthquake

    题意:两地之间有n条不相交路径,第i条路径由a[i]座桥组成,每座桥有一个损坏概率,让你确定一个对所有桥的检测顺序,使得检测所需的总期望次数最小. 首先,显然检测的时候,是一条路径一条路径地检测,跳跃 ...

  3. 【线段树】【扫描线】Petrozavodsk Winter Training Camp 2018 Day 5: Grand Prix of Korea, Sunday, February 4, 2018 Problem A. Donut

    题意:平面上n个点,每个点带有一个或正或负的权值,让你在平面上放一个内边长为2l,外边长为2r的正方形框,问你最大能圈出来的权值和是多少? 容易推出,能框到每个点的 框中心 的范围也是一个以该点为中心 ...

  4. 2015-2016 Petrozavodsk Winter Training Camp, Nizhny Novgorod SU Contest (5/9)

    2015-2016 Petrozavodsk Winter Training Camp, Nizhny Novgorod SU Contest B. Forcefield 题意 给你一维平面上n个镜子 ...

  5. 2014-2015 Petrozavodsk Winter Training Camp, Contest.58 (Makoto rng_58 Soejima contest)

    2014-2015 Petrozavodsk Winter Training Camp, Contest.58 (Makoto rng_58 Soejima contest) Problem A. M ...

  6. 2015 UESTC Winter Training #7【2010-2011 Petrozavodsk Winter Training Camp, Saratov State U Contest】

    2015 UESTC Winter Training #7 2010-2011 Petrozavodsk Winter Training Camp, Saratov State U Contest 据 ...

  7. Petrozavodsk Summer Training Camp 2017 Day 9

    Petrozavodsk Summer Training Camp 2017 Day 9 Problem A. Building 题目描述:给出一棵树,在树上取出一条简单路径,使得该路径的最长上升子序 ...

  8. Petrozavodsk Summer Training Camp 2017

    Petrozavodsk Summer Training Camp 2017 Problem A. Connectivity 题目描述:有\(n\)个点,现不断地加边.每条边有一种颜色,如果一个点对\ ...

  9. Petrozavodsk Winter Training Camp 2018

    Petrozavodsk Winter Training Camp 2018 Problem A. Mines 题目描述:有\(n\)个炸弹放在\(x\)轴上,第\(i\)个位置为\(p_i\),爆炸 ...

随机推荐

  1. 安装magento配置完数据库后出现: PHP Extensions "0" must be loaded. 解决方案

    打开magento目录下的该文件: app/code/core/Mage/Install/etc/config.xml 将下面该段修改: <mysql4> <type>pdo_ ...

  2. HDU 1234 开门人和关门人 (模拟)

    题目链接 Problem Description 每天第一个到机房的人要把门打开,最后一个离开的人要把门关好.现有一堆杂乱的机房签  到.签离记录,请根据记录找出当天开门和关门的人.    Input ...

  3. bzoj 3197 DP

    这道题我们可以看成给定两个黑白树,可以修改其中一棵树的颜色,问最少修改多少颜色可以使两棵树同构. 首先我们知道在树的同构中树上最长链中点(如果是偶数的话就是中间两个点)是不变的,我们把这个点叫做树的重 ...

  4. js jq插件 显示中文时间戳 刚刚 N分钟前 N小时前 今天 上午 下午 日期格式化

    注:页面需提前引用JQ ; $.fn.extend({ /* ** notes: 获取13位时间戳的简单操作 ** new Date('2018-02-01 15:10:00').getTime() ...

  5. 关于this问题

    对于关键字this,其实很好理解,谁调用我就指向谁.下面举个例子说明: 其实这也是在学习闭包中的一个案例: var name = "The window"; var obj = { ...

  6. 【转】MP3文件原理及结构解析

    1.引言文件压缩技术的日新月异使得MP3成为时下最烫手的音乐格式,优质的音乐随着0与1的排列迅速散布 到世界各地,撼动人心.何谓MP3?MP3的全称是MPEG Audio Layer 3,它是一种高效 ...

  7. Java的9种基本数据类型的大小,以及他们的封装类

    由于java程序是运行在虚拟机之上的,所以java的基本数据类型的大小是确定的,不会随着操作系统的位数的改变而改变. 在计算机中,存储的是0,1,0,1这样的二进制位,表示为bit,1Byte = 8 ...

  8. 【Windows使用笔记】Windows日常使用软件

    整理一些对于我来说日常使用的Windows软件. 排名不分先后,仅凭我想起来的顺序! 1 MadAppLauncher 这个对我来说非常需要了. 使用它可以快速启动日常常用的软件,非常快捷高效.一般来 ...

  9. 动态替换Linux核心函数的原理和实现

    转载:https://www.ibm.com/developerworks/cn/linux/l-knldebug/ 动态替换Linux核心函数的原理和实现 在调试Linux核心模块时,有时需要能够实 ...

  10. device tree source file position

    android/kernel/msm-4.9/arch/arm64/boot/dts/qcom/