CF1062F Upgrading Cities

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;
}
posted @ 2019-06-16 16:50  comld  阅读(167)  评论(0编辑  收藏  举报