题目来源: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 ...
随机推荐
-
[Asp.net 5] Caching-缓存预告
本节讲Asp.net 5的缓冲.解决方案可以通过网址:https://github.com/aspnet/Caching下载 也是Asp.net 5开源代码介绍的第6部分,前5部分链接如下: 1. D ...
-
JAVA中int、String的类型相互转换
int -> String int i=12345;String s="";第一种方法:s=i+"";第二种方法:s=String.valueOf(i); ...
-
通过CSS禁用页面模块的复制和粘贴功能
样式代码: -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; -khtml-user-select: ...
-
VB 读取csv文件数据
Public adoConn As New ADODB.Connection Private Sub csv() adoConn.ConnectionString = "Driver={Mi ...
-
用于模拟百度分享的errno错误代码
0:成功;-1:由于您分享了违反相关法律法规的文件,分享功能已被禁用,之前分享出去的文件不受影响.;-2:用户不存在;请刷新页面后重试;-3:文件不存在;请刷新页面后重试;-4:登录信息有误,请重新登 ...
-
FinalizableReference, FinalizablePhantomReference, FinalizableReferenceQueue
FinalizableReference /* * Copyright (C) 2007 The Guava Authors * * Licensed under the Apache License ...
-
分布式交易系统的并发处理, 以及用Redis和Zookeeper实现分布式锁
交易系统 交易系统的数据结构 支付系统API通常需要一个“订单号”作为入参, 而实际调用API接口时使用到的往往不是真正意义的业务订单号, 而是交易订单号. 支付系统的API会使用“商户号+订单号” ...
-
Java Swing实战(四)按钮组件JButton及其事件监听
接下来为面板添加保存按钮,并为按钮绑定事件监听. /** * @author: lishuai * @date: 2018/11/26 13:51 */ public class WeimingSyn ...
-
python学习 (三十二) 异常处理
1 异常: def exceptionHandling(): try: a = b = d = a / b print(d) except ZeroDivisionError as ex: print ...
-
六个比较好用的php数组Array函数
1. array_column 返回输入数组中某个单一列的值.2. array_filter 用回调函数过滤数组中的元素.3. array_map 将用户自定义函数作用到给定数组的每个值上,返回新的值 ...