Birdwatching

题目链接:Birdwatching


显然,只有直接与T相连的点,才可能成为答案。

对于一个点,可以成为答案,那么证明他可以到其他与T直接相邻的点。所以我们只需要知道每个点是否可以由直接与T相邻的点到达,所以建立反图,然后二进制分组即可。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
//#define int long long
using namespace std;
const int N=1e5+10;
int n,m,s,vis[N],mark[N],st[N];
vector<int> g[N],res,v;	queue<int> q;
inline void bfs(){
	while(q.size()){
		int u=q.front();	q.pop();
		for(auto to:g[u])	if(!vis[to]&&to!=s)	vis[to]=1,q.push(to);
	}
	for(int i=1;i<=n;i++)	if(mark[i]&&vis[i])	st[i]=1;
}
signed main(){
	cin>>n>>m>>s;	s++;
	for(int i=1,a,b;i<=m;i++){
		scanf("%d %d",&a,&b),a++,b++,g[b].push_back(a);
		if(b==s)	v.push_back(a);
	}
	for(int s=0;s<=17;s++){
		memset(vis,0,sizeof vis),memset(mark,0,sizeof mark);
		for(int i=0;i<v.size();i++){
			if(v[i]>>s&1)	q.push(v[i]),vis[v[i]]=1;
			else	mark[v[i]]=1;
		}
		bfs();
		memset(vis,0,sizeof vis),memset(mark,0,sizeof mark);
		for(int i=0;i<v.size();i++){
			if(!(v[i]>>s&1))	q.push(v[i]),vis[v[i]]=1;
			else	mark[v[i]]=1;
		}
		bfs();
	}
	for(int i=0;i<v.size();i++)	if(!st[v[i]])	res.push_back(v[i]);
	sort(res.begin(),res.end());
	cout<<res.size()<<endl;
	for(auto i:res)	printf("%d\n",i-1);
	return 0;
}

你可能感兴趣的:(图论,二进制分组,bfs)