http://codeforces.com/problemset/problem/1062/F
题解
有意思的题。
首先考虑在\(DAG\)上拓扑的过程,设当前队列中的点集为\(S\),那么有结论是这些点之间都不能互相到达,这个比较好理解。
那么我们考虑在弹出一个点的时候计算它能够到达多少点,如果当前队列里有超过一个点,那它肯定就不行了。
如果一个点都没有,那么剩下的点他都可以访问。
如果只有一个点,那么看一下那个点的所有出点,如果有一个点的入度为1,说明当前这个点一定不能到达,否则一定全都能到达,这个可以手画理解一下。
但是还要计算它被多少点到达,这个反着拓扑一下就好了。
代码
#include<bits/stdc++.h>
#define N 300009
using namespace std;
typedef long long ll;
queue<int>q;
int n,m,du1[N],du2[N],ans,f[N];
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
std::vector<int>vec1[N],vec2[N];
std::vector<int>::iterator it;
inline void add(int u,int v){
vec1[u].push_back(v);du1[v]++;
vec2[v].push_back(u);du2[u]++;
}
int main(){
n=rd();m=rd();
for(int i=1;i<=n;++i)f[i]=1;
int u,v;
for(int i=1;i<=m;++i){
u=rd();v=rd();
add(u,v);
}
int now=n;
for(int i=1;i<=n;++i)if(!du1[i])q.push(i),now--;
while(!q.empty()){
int u=q.front();q.pop();
if(!q.size())f[u]+=now;
else if(q.size()==1){
int v=q.front(),o=0;
for(it=vec1[v].begin();it!=vec1[v].end();++it){
int w=*it;
if(du1[w]==1){o=1;break;}
}
if(!o)f[u]+=now;
}
for(it=vec1[u].begin();it!=vec1[u].end();++it){
int v=*it;
if(!--du1[v])q.push(v),now--;
}
}
now=n;
for(int i=1;i<=n;++i)if(!du2[i])q.push(i),now--;
while(!q.empty()){
int u=q.front();q.pop();
if(!q.size())f[u]+=now;
else if(q.size()==1){
int v=q.front(),o=0;
for(it=vec2[v].begin();it!=vec2[v].end();++it){
int w=*it;
if(du2[w]==1){o=1;break;}
}
if(!o)f[u]+=now;
}
for(it=vec2[u].begin();it!=vec2[u].end();++it){
int v=*it;
if(!--du2[v])q.push(v),now--;
}
}
for(int i=1;i<=n;++i){
if(f[i]>=n-1)ans++;
}
cout<<ans<<endl;
return 0;
}