将每条双向边拆成两条单向边,若两条边中至少存在一条边使得删掉它之后图中SCC个数不变,则这条边可以定向。

将边中间加上点,变成删点问题。

对于每个SCC单独考虑,随便选择一个不是拆点出来的点S作为源。

则在正图或者反图的Dominator Tree上的所有非叶子节点均会影响连通性。

用Lengauer-Tarjan算法求出Dominator Tree即可。

时间复杂度$O((n+m)\alpha(n+m))$。

#include<cstdio>
const int N=500010,M=800010;
int n,m,lim,i,x,y,z,ans;bool vis[N],cut[N];
int g0[N],g1[N],v[M*2],nxt[M*2],ed,f[N],q[N],t,size,now[N],rk[N];
namespace DT{
int n,g1[N],g2[N],gd[N],v[M*3+N],nxt[M*3+N],ed;
int cnt,dfn[N],id[N],fa[N],f[N],mn[N],sd[N],idom[N];
inline void add(int*g,int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
inline void add(int x,int y){add(g1,x,y);add(g2,y,x);}
int F(int x){
if(f[x]==x)return x;
int y=F(f[x]);
if(sd[mn[x]]>sd[mn[f[x]]])mn[x]=mn[f[x]];
return f[x]=y;
}
void dfs(int x){
id[dfn[x]=++cnt]=x;
for(int i=g1[x];i;i=nxt[i])if(!dfn[v[i]])dfs(v[i]),fa[dfn[v[i]]]=dfn[x];
}
inline void tarjan(int S){
int i,j,k,x;
for(cnt=0,i=1;i<=n;i++)gd[i]=dfn[i]=id[i]=fa[i]=idom[i]=0,f[i]=sd[i]=mn[i]=i;
dfs(S);
for(i=n;i>1;i--){
for(j=g2[id[i]];j;j=nxt[j])F(k=dfn[v[j]]),sd[i]=sd[i]<sd[mn[k]]?sd[i]:sd[mn[k]];
add(gd,sd[i],i);
for(j=gd[f[i]=x=fa[i]];j;j=nxt[j])F(k=v[j]),idom[k]=sd[mn[k]]<x?mn[k]:x;
gd[x]=0;
}
for(i=2;i<=n;add(gd,idom[i],i),i++)if(idom[i]!=sd[i])idom[i]=idom[idom[i]];
}
inline void init(int _n){
n=_n;ed=0;
for(int i=1;i<=n;i++)g1[i]=g2[i]=0;
}
}
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void add(int x,int y){
v[++ed]=y;nxt[ed]=g0[x];g0[x]=ed;
v[++ed]=x;nxt[ed]=g1[y];g1[y]=ed;
}
void dfs1(int x){
vis[x]=1;
for(int i=g0[x];i;i=nxt[i])if(!vis[v[i]])dfs1(v[i]);
q[++t]=x;
}
void dfs2(int x,int y){
vis[x]=0,f[x]=y;
now[rk[x]=++size]=x;
for(int i=g1[x];i;i=nxt[i])if(vis[v[i]])dfs2(v[i],y);
}
inline void solve(int o){
int i,j;
for(i=1;i<=size;i++)if(now[i]>lim)break;
if(i>size)return;
DT::init(size);
for(i=1;i<=size;i++)for(j=g0[now[i]];j;j=nxt[j])if(f[v[j]]==o)DT::add(i,rk[v[j]]);
for(i=1;i<=size;i++)if(now[i]<=lim){
DT::tarjan(i);
break;
}
for(i=1;i<=size;i++)if(DT::gd[DT::dfn[i]])cut[now[i]]=1;
DT::init(size);
for(i=1;i<=size;i++)for(j=g0[now[i]];j;j=nxt[j])if(f[v[j]]==o)DT::add(rk[v[j]],i);
for(i=1;i<=size;i++)if(now[i]<=lim){
DT::tarjan(i);
break;
}
for(i=1;i<=size;i++)if(DT::gd[DT::dfn[i]])cut[now[i]]=1;
}
int main(){
read(n),read(m);lim=n;
while(m--){
read(x),read(y),read(z);
if(x==y){ans+=z==2;continue;}
if(z==1)add(x,y);
else{
add(x,++n);
add(n,y);
add(y,++n);
add(n,x);
}
}
for(i=1;i<=n;i++)if(!vis[i])dfs1(i);
for(i=n;i;i--)if(vis[q[i]]){
size=0;
dfs2(q[i],q[i]);
solve(q[i]);
}
for(i=lim+1;i<=n;i+=2)if(!cut[i]||!cut[i+1])ans++;
return printf("%d",ans),0;
}

  

BZOJ2861 : 双向边定向为单向边的更多相关文章

  1. SSL双向认证和SSL单向认证的流程和区别

    refs: SSL双向认证和SSL单向认证的区别https://www.jianshu.com/p/fb5fe0165ef2 图解 https 单向认证和双向认证!https://cloud.tenc ...

  2. 什么是SSL双向认证,与单向认证证书有什么区别?

    SSL/TLS证书是用于用户浏览器和网站服务器之间的数据传输加密,实现互联网传输安全保护,大多数情况下指的是服务器证书.服务器证书是用于向浏览器客户端验证服务器,这种是属于单向认证的SSL证书.但是, ...

  3. Python 双向队列Deque、单向队列Queue 模块使用详解

    Python 双向队列Deque 模块使用详解 创建双向队列Deque序列 双向队列Deque提供了类似list的操作方法: #!/usr/bin/python3 import collections ...

  4. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  5. https单向认证和双向认证

    单向认证: .clinet<--server .clinet-->server .client从server处拿到server的证书,通过公司的CA去验证该证书,以确认server是真实的 ...

  6. 基于openssl的单向和双向认证

    1.前言 最近工作涉及到https,需要修改nginx的openssl模块,引入keyless方案.关于keyless可以参考CloudFlare的官方博客: https://blog.cloudfl ...

  7. 单向和双向tvs管

    tvs管器件按极性可分为单极性和双极性两种,即单向tvs管和双向tvs管.    单向tvs管保护器件仅能对正脉冲或者负脉冲进行防护,而双向tvs管保护器件一端接要保护的线路,一端接地,无论来自反向还 ...

  8. SSL单向认证和双向认证说明

    SSL单向认证和双向认证说明 一.SSL双向认证具体过程 浏览器发送一个连接请求给安全服务器. 服务器将自己的证书,以及同证书相关的信息发送给客户浏览器. 客户浏览器检查服务器送过来的证书是否是由自己 ...

  9. ORACLE GoldenGate在Windows与AIX平台ORACLE的单向、双向数据传输配置及其测试

    第1章...... GoldenGate概述 1.1         GoldenGate技术原理 1.2         GoldenGate可靠的复制 1.3         GoldenGate ...

随机推荐

  1. python的技巧和方法你了解多少?

    学了这些你的python代码将会改善与你的技巧将会提高. 1. 路径操作 比起os模块的path方法,python3标准库的pathlib模块的Path处理起路径更加的容易. 获取当前文件路径 前提导 ...

  2. 域名调整 SEO优化(nginx)

    =============================================== 2019/3/31_第1次修改                       ccb_warlock == ...

  3. HTTP基础知识2

    引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...

  4. ThinkPHP使用不当可能造成敏感信息泄露

    ThinkPHP在开启DEBUG的情况下会在Runtime目录下生成日志,如果debug模式不关,可直接输入路径造成目录遍历. ThinkPHP3.2结构:Application\Runtime\Lo ...

  5. 【Android开源库】美团等APP城市选择

    CityPicker 现在使用比较多的类似美团等APP的城市选择界面. 2步即可实现,就是这么简单粗暴! Gif image APK 下载demo.apk体验. Install Gradle: com ...

  6. IE 浏览器 GET 请求缓存问题

    问题描述 IE 浏览器(笔者使用的版本是 IE 11)在发起 GET 请求,当参数一样时,浏览器会直接使用缓存数据,这样对于实时性有要求的数据不适用.笔者在使用 Chrome 或 FF 时发现浏览器并 ...

  7. hdu4812 逆元+树分治

    逆元链接:https://www.cnblogs.com/zzqc/p/7192436.html 经典的树分治题 #pragma comment("linker,"/STACK:1 ...

  8. 步步为营-33-Md5(32)加密与Base64加密

    说明: 1:直接贴码 using System; using System.Collections.Generic; using System.ComponentModel; using System ...

  9. 向集合中添加Person类型并对其排序

    package com.bjpowernode.t03sort; import java.util.ArrayList;import java.util.Collections; /* * 向集合中添 ...

  10. HDU 1029 某个数出现的次数大于等于(N+1)/2的是哪个 map水题

    题意:输入n个数 n为奇数 问某个数出现的次数大于等于(N+1)/2的是 哪个 输出来Sample Input51 3 2 3 3111 1 1 1 1 5 5 5 5 5 571 1 1 1 1 1 ...