NOIp模拟赛 现实(DP 拓扑)
题目来源:by lzz
\(Description\)
给定一张有向图,求对于哪些点,删除它和它的所有连边后,图没有环。
\(n\leq 5\times10^5,m\leq 10^6\)。
\(Solution\)
题目等价于求所有环的交集。
首先两个特判:如果原图没有环,输出所有点;如果删掉原图的某个环后,仍存在环,输出\(0\)。这也是不少分了。
先求出图中的某个环,环交当然在这个环上。我们只需要处理这个环。
把环拆成链,发现所有除它外的环只有两种情况:
对于第一种情况,
如果做过这个链的Subtask,很容易发现(倒也显然)合法的点只可能是这些环的交集(把红边看成线段,就是求区间的交)。之前的第二次判环可以拓扑,然后利用拓扑序从出度为0的点更新能到它的点的最左位置\(pl\)、从入度为0的点更新它到的点的最右位置\(pr\)。然后就可以找到最右的左端点和最靠左的右端点。
对于第二种情况,
显然,如果存在红边\(x\rightarrow y\),则\(x,y\)之间的点都不是合法的。
依旧利用拓扑序从出度为0的点更新到它的点的最右位置\(pr\),然后扫一遍。
两种情况都合法的点就是答案了。
发现图中只有两个环,且环交为1个点时,这个点是合法的,但是删掉环边后图仍存在环,会返回无解。我们发现如果将每个点拆成入点和出点,这种情况就可以处理了。即把环交从点集变成边集。
复杂度\(O(n+m)\)。
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1e6+5,M=1e6+5+N;
int n,m,Enum,H[N],nxt[M],to[M],dgr[N],cir[N],sz,pre[N],fa[N],q[N],pl[N],pr[N];
bool find_circle,vis[N],ins[N],isc[M],ok[N];
std::vector<int> ans;
char IN[MAXIN],*SS=IN,*TT=IN;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void AE(int v,int u)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
}
void DFS(int x)
{
vis[x]=ins[x]=1;
for(int i=H[x],v; i; i=nxt[i])
if(!vis[v=to[i]])
{
fa[v]=x, pre[v]=i, DFS(v);
if(find_circle) return;
}
else if(ins[v])
{
for(int p=x; p!=v; p=fa[p]) cir[++sz]=p, isc[pre[p]]=1;
cir[++sz]=v, isc[i]=1;
std::reverse(cir+1,cir+1+sz);
find_circle=1; return;
}
ins[x]=0;
}
bool Toposort()
{
int h=0,t=0;
for(int i=1; i<=Enum; ++i) if(!isc[i]) ++dgr[to[i]];//度也是删环后的!
for(int i=1; i<=n; ++i) if(!dgr[i]) q[t++]=i;
while(h<t)
{
int x=q[h++];
for(int i=H[x]; i; i=nxt[i])
if(!isc[i] && !--dgr[to[i]]) q[t++]=to[i];
}
return t==n;
}
void Solve()
{
for(int i=1; i<=n; ++i)
if(!vis[i]) {DFS(i); if(find_circle) break;}
if(!find_circle)
{
n>>=1;
for(int i=1; i<=n; ++i) ans.push_back(i);
return;
}
if(!Toposort()) return;
int ansl=1,ansr=sz;
for(int i=1; i<=sz; ++i) pl[cir[i]]=pr[cir[i]]=i;
for(int i=n,x; i; --i)
{
if(!pl[x=q[i]]) pl[x]=N;//避免环外的影响
for(int j=H[x]; j; j=nxt[j])
if(!isc[j]/*!*/) pl[x]=std::min(pl[x],pl[to[j]]);//非环边!又忘判了
}
for(int i=1; i<=sz; ++i)
if(pl[cir[i]]<i) {ansr=i; break;}//对于左端端点应该有pl[i]==i
for(int i=1,x; i<=n; ++i)
{
// if(!pr[x=q[i]]) pr[x]=0;
for(int j=H[x=q[i]]; j; j=nxt[j])
if(!isc[j]) pr[to[j]]=std::max(pr[to[j]],pr[x]);
}
for(int i=sz; i; --i)
if(pr[cir[i]]>i) {ansl=i; break;}
if(ansl>ansr) return;
memset(pr,0,sizeof pr);
for(int i=1; i<=sz; ++i) pr[cir[i]]=i;
for(int i=n,x; i; --i)//对另一个方向的pr再求一次
{
// if(!pr[x=q[i]]) pr[x]=0;
for(int j=H[x=q[i]]; j; j=nxt[j])
if(!isc[j]) pr[x]=std::max(pr[x],pr[to[j]]);
}
int nowr=0;
for(int i=1; i<=sz; ++i)
{
if(i>=nowr) ok[i]=1;
nowr=std::max(nowr,pr[cir[i]]);
}
for(int i=ansl; i<ansr; i+=2) if(ok[i]) ans.push_back(cir[i]);//ansl一定是个入点
std::sort(ans.begin(),ans.end());
}
int main()
{
n=read();
for(int i=1; i<=n; ++i) AE(i+n,i);//in:x out:x+n 参数顺序!
for(int m=read(); m--; AE(read(),read()+n));
n<<=1, Solve();
printf("%d\n",ans.size());
for(int i=0,l=ans.size(); i<l; ++i) printf("%d ",ans[i]);
return 0;
}
NOIp模拟赛 现实(DP 拓扑)的更多相关文章
- 放棋游戏(NOIP模拟赛)(DP)
没有原题... 囧.. [问题描述] 游戏规则是这样,有n(1<=n<=100)行格子,第一行由n个格子,第二行有n-1个格子,第三行由n-2个格子,……以此类推,第n行有1个格子.要求再 ...
- 【noip模拟赛5】细菌 状压dp
[noip模拟赛5]细菌 描述 近期,农场出现了D(1<=D<=15)种细菌.John要从他的 N(1<=N<=1,000)头奶牛中尽可能多地选些产奶.但是如果选中的奶牛携 ...
- NOIP模拟赛20161022
NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...
- NOIP模拟赛 by hzwer
2015年10月04日NOIP模拟赛 by hzwer (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...
- 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程
数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...
- 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1
题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...
- 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1
题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...
- CH Round #58 - OrzCC杯noip模拟赛day2
A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...
- CH Round #52 - Thinking Bear #1 (NOIP模拟赛)
A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...
随机推荐
- js的正则表达式编程,悬赏解决下面的问题
悬赏解决下面的问题 1.切分url 2.将时间日期 转化为 yyyy-MM-dd的模式和可逆性 3.数据的千分位和可逆性 4.用C#或者nodejs检索如下的模式 h1{ border:1px sol ...
- MySQL日志——Undo | Redo【转】
本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版 ...
- GetStockObject 理解
原文地址:https://www.cnblogs.com/Clingingboy/archive/2013/04/13/3017952.html GetStockObject在图形编程中是常用API之 ...
- centos环境自动化批量安装jdk软件脚本
自动化安装jdk软件部署脚本 准备工作: 1.在执行脚本的服务器上生成免密码公钥: 安装expect命令 yum install -y expect ssh-keygen 三次回车 2.将jdk-7u ...
- Python-JS事件与面向对象操作
目录一.函数高级 循环绑定: 使用循环绑定会出现的问题及解决方案: 二.面向对象 3.构造函数(ES5) 三.JS选择器 1.getElement系列(最严谨) 2.querySelector系列(最 ...
- 石头剪刀布三局两胜(平局重来break用法)
- 为什么js中0.1+0.2不等于0.3,怎样处理使之相等?(转载)
为什么js中0.1+0.2不等于0.3,怎样处理使之相等? console.log(0.1+0.2===0.3)// true or false?? 在正常的数学逻辑思维中,0.1+0.2=0.3这个 ...
- CF126B
CF126B Password 题意: 给出一个字符串 H,找一个最长的字符串 h,使得它既作为前缀出现过.又作为后缀出现过.还作为中间的子串出现过. 解法: 沿着 $ next_n $ 枚举字符串, ...
- AlexNet
AlexNet学习笔记 目录 AlexNet整体结构 CNN 全连接 TensorFlow实现 AlexNet是2012年ImageNet竞赛冠军获得者Hinton和他的学生Alex Krizhevs ...
- Optimization algorithm----Deep Learning
深度学习中的优化算法总结 以下内容简单的汇总了在深度学习中常见的优化算法,每个算法都集中回答:是什么?(原理思想)有什么用?(优缺点)怎么用?(在tensorflow中的使用) 目录 1.SGD 1. ...