题目来源: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. Theano教程:Python的内存管理

    在写大型程序时候的一大挑战是如何保证最少的内存使用率.但是在Python中的内存管理是比较简单的.Python显示分配内存,使用引用计数系统管理对象,当指向某一个对象的引用数变为 0 的时候,该对象所 ...

  2. char *与const char **函数参数传参问题

    传参方法 ## 函数 extern void f2 ( const char ** ccc ); const char ch = 'X'; char * ch_ptr; const char ** c ...

  3. dup,dup2函数【转】

    转自:http://eriol.iteye.com/blog/1180624 转自:http://www.cnblogs.com/jht/archive/2006/04/04/366086.html ...

  4. mysql系列二、mysql内部执行过程

    向MySQL发送一个请求的时候,MySQL到底做了什么 客户端发送一条查询给服务器. 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果.否则进入下一阶段. 服务器端进行SQL解析.预 ...

  5. sqlserver 备份 与 还原

    背景 真是够懒得,一看这个内容,如此简单.当时的想法就是网上教程一堆,全记下来有啥意思,只是记录了要点.不过写到这里,也就写个别的吧.sqlserver与Oracle比起来,我感觉有个重要差距就是存储 ...

  6. 转载:分布式文件系统 - FastDFS 在 CentOS 下配置安装部署(2)

    原文:http://blog.mayongfa.cn/193.html 一.安装 Nginx 和 fastdfs-nginx-module 安装 Nginx 请看:从零开始学 Java - CentO ...

  7. gitlab代码仓库迁移

    有的时候我们需要对gitlab上的代码进行迁移,希望在迁移后能保持原有的branch.tag.commit记录等.可以使用以下方式: 1.clone代码到本地. 2.修改remote仓库的地址,添加新 ...

  8. Android学习笔记————利用JDBC连接服务器数据库

    /******************************************************************************************** * auth ...

  9. 转:10分钟了解JS堆、栈以及事件循环的概念

    https://juejin.im/post/5b1deac06fb9a01e643e2a95?utm_medium=fe&utm_source=weixinqun 前言 其实一开始对栈.堆的 ...

  10. vue首次赋值不触发watch

    可通过其immediate 属性进行配置,默认为false watch:{ "aaa":{ immediate:true, handler:function(){ } }