题目大意
求删去一个点后图变成DAG这样的点的所有选择方案。
分析
P20
暴力枚举每个点,
然后拓扑排序查看是否为DAG。
P40
这一档满足有一条链从1连到n,有一条边为(n,1)。
其实就是一个大环。
这样其他的边形成的环是很明显的。
所以直接枚举点,然后查看是否被所有这样的边包含即可。
随便找个什么数据结构都能维护。
差分可以写得比较方便。
P100
可知现在找的点必须要使当前图上所有环消失。
因此它肯定在一个环上,
这时进行一个简单的处理,裂一个点为入点与出点,
那么删除该边与删除该点的效果是相同的。
然后就随便找一个环(找不到说明原来就是个DAG。
再删掉这个环上所有的边,
对剩下的点进行拓扑排序。
如果还不是DAG则肯定无解。
然后根据这个拓扑序来对每个点求解其能通过非环边到达的位置。
将这个二元组看作一条环上的有方向的边。
于是变成了P40的情况,同样差分维护。
代码
初始化失误调了很久= =
#include<bits/stdc++.h>
using namespace std;
#define Komachi is retarded
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)
#define INF 0x3f3f3f3f
#define chkmax(a,b) a=max(a,b)
#define chkmin(a,b) a=min(a,b)
#define M 1000004
void Rd(int &res){
char c;res=0;
while((c=getchar())<48);
do res=(res<<3)+(res<<1)+(c^48);
while((c=getchar())>47);
}
int n,m,N;
int Next[M<<1],V[M<<1],Head[M],tot;
void Add_Edge(int u,int v){
Next[++tot]=Head[u],V[Head[u]=tot]=v;
}
#define LREP(i,A) for(int i=Head[A];i;i=Next[i])
int Pre[M],Fa[M],Ans[M],ans;
int C[M],Clen;
bool FindC,Use[M<<1];
int Vis[M];
void Circle(int A){
Vis[A]=1;
LREP(i,A){
int B=V[i];
if(Vis[B]==0){
Fa[B]=A;
Pre[B]=i;
Circle(B);
}
else if(Vis[B]==1){
int x=A;
Use[i]=1;
while(x!=B){
C[Clen++]=x;
Use[Pre[x]]=1;
x=Fa[x];
}
C[Clen++]=B;
FindC=1;
}
if(FindC)return;
}
Vis[A]=2;
}
int Deg[M],Tp[M],LT,Tlen;
bool Topo(){
REP(i,1,N+1) LREP(j,i) if(!Use[j]) Deg[V[j]]++;
REP(i,1,N+1) if(!Deg[i]) Tp[Tlen++]=i;
while(LT<Tlen) LREP(i,Tp[LT++]) if(!Use[i] && !(--Deg[V[i]]))
Tp[Tlen++]=V[i];
return Tlen==N;
}
int Mn[M],Mx[M],Fr[M],Sum[M];
void Solve(){
REP(i,1,n+1)if(!Vis[i]){
Circle(i);
if(FindC)break;
}
if(!FindC){
REP(i,1,n+1)
Ans[ans++]=i;
return;
}
if(!Topo())return;
memset(Mn,63,sizeof(Mn));
memset(Mx,-1,sizeof(Mx));
memset(Fr,-1,sizeof(Fr));
reverse(C,C+Clen);
REP(i,0,Clen)Mn[C[i]]=Mx[C[i]]=Fr[C[i]]=i;
int A;
DREP(i,N-1,-1) LREP(j,A=Tp[i]) if(!Use[j]) chkmin(Mn[A],Mn[V[j]]),chkmax(Mx[A],Mx[V[j]]);
REP(i,0,N) LREP(j,A=Tp[i]) if(!Use[j]) chkmax(Fr[V[j]],Fr[A]);
REP(i,0,Clen){
A=C[i];
if(Mn[A]<i){
Sum[0]++,Sum[Mn[A]+1]--;
Sum[i+1]++;
}
if(Mx[A]>i){
Sum[i+1]++;
Sum[Mx[A]+1]--;
}
if(Fr[A]>i){
Sum[0]++,Sum[i]--;
Sum[Fr[A]+1]++;
}
}
REP(i,0,Clen){
Sum[i+1]+=Sum[i];
if(!Sum[i] && C[i]>n)Ans[ans++]=C[i]-n;
}
}
int main(){
Rd(n),Rd(m);N=n<<1;
REP(i,1,n+1)Add_Edge(i,i+n);
REP(i,0,m){
int u,v;
Rd(u),Rd(v);
Add_Edge(u+n,v);
}
Solve();
printf("%d\n",ans);
sort(Ans,Ans+ans);
REP(i,0,ans)
printf("%d%c",Ans[i]," \n"[i==ans-1]);
return 0;
}