题目来源: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 拓扑)的更多相关文章

  1. 放棋游戏(NOIP模拟赛)(DP)

    没有原题... 囧.. [问题描述] 游戏规则是这样,有n(1<=n<=100)行格子,第一行由n个格子,第二行有n-1个格子,第三行由n-2个格子,……以此类推,第n行有1个格子.要求再 ...

  2. 【noip模拟赛5】细菌 状压dp

    [noip模拟赛5]细菌   描述 近期,农场出现了D(1<=D<=15)种细菌.John要从他的 N(1<=N<=1,000)头奶牛中尽可能多地选些产奶.但是如果选中的奶牛携 ...

  3. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  4. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  5. 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程

    数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...

  6. 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  7. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  8. CH Round #58 - OrzCC杯noip模拟赛day2

    A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...

  9. CH Round #52 - Thinking Bear #1 (NOIP模拟赛)

    A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...

随机推荐

  1. 如何用ModelsimSE仿真IP核-以PLL为例

    我们之前介绍了如何使用Modelsim SE进行仿真和利用do文件的仿真方法,但是其中待仿真的模块是我们自己编写的Verilog模块,但是在实际工作中,我们的设计中会经常用到FPGA厂商给我们提供的现 ...

  2. Python算法:推导、递归和规约

    Python算法:推导.递归和规约 注:本节中我给定下面三个重要词汇的中文翻译分别是:Induction(推导).Recursion(递归)和Reduction(规约) 本节主要介绍算法设计的三个核心 ...

  3. 解析如何在C语言中调用shell命令的实现方法【转】

    本文转自:http://www.jb51.net/article/37404.htm 1.system(执行shell 命令)相关函数 fork,execve,waitpid,popen表头文件 #i ...

  4. centos系统中perl进程病毒占用大量网络流量导致网络瘫痪的问题分析及解决方案

    故障现象: 1.系统在早上9点的时候非常慢,单台服务器占用流量很大,使交换机流量被占满,而连累挂在同一交换机上的其他应用也无法提供服务,或者速度非常慢     2.通过查看进程发现大量的perl程序占 ...

  5. Expm 8_1 区间划分问题

      [问题描述] 给定一组报告,其中的每个报告设置了一个开始时间si和结束时间fi.设计与实现一个算法,对这组报告分配最少数量的教室,使得这些报告能无冲突的举行. package org.xiu68. ...

  6. passive 的事件监听器(转载)

    passive 的事件监听器 很久以前,addEventListener() 的参数约定是这样的: addEventListener(type, listener, useCapture) 后来,最后 ...

  7. Java中BigDecimal类介绍及用法

    Java中提供了大数字(超过16位有效位)的操作类,即 java.math.BinInteger 类和 java.math.BigDecimal 类,用于高精度计算. 其中 BigInteger 类是 ...

  8. poj2342 没有上司的舞会 树形dp基础

    #include<iostream> #include<cstring> #include<cstdio> #include<vector> using ...

  9. graphql详解

    随着系统业务量的增大不同的应用和系统共同使用着许多的服务api,而随着业务的变化和发展,不同的应用对相同资源的不同使用方法最终会导致需要维护的服务api数量呈现爆炸式的增长,比如我试着跑了下我们自己业 ...

  10. Jmeter NonGUI模式

    一般情况下我们都是在NonGUI模式下运行jmeter.这样做有两个好处 节省系统资源,能够产生更大的负载 可以通过命令行参数对测试场景进行更精细的配置 示例 创建luzhi.jmx脚本 jmeter ...