1. 程式人生 > >【拓撲排序】【bitset】Gym - 101128A - Promotions

【拓撲排序】【bitset】Gym - 101128A - Promotions

cnblogs int turn names std amp class ans bitset

給你一張DAG,若選擇u點,則必須先選擇所有能到達其的點。問你在選擇A個點的情況下,哪些點必選;選擇B個點的情況下,哪些點必選;選擇B個點的情況下,哪些點一定不選。

選擇A個點的情況,必選的點是那些其所能到達的點數>n-A的點。

選B個點,必選的點與前者類似。

一定不選的點,是能到達它的點數>B的點。

處理一個點所能到達的點數,要麽暴力,也可以可以將邊反向後,對每個點搞個bitset來做。

一個DAG反向後仍是DAG。

#include<cstdio>
#include<bitset>
#include<queue>
using namespace std;
bitset<5010>S[5010];
queue<int>q;
int first[5010],e,next[20010],v[20010],siz[5010],si2[5010];
void AddEdge(int U,int V){
	v[++e]=V;
	next[e]=first[U];
	first[U]=e;
}
int firs2[5010],e2,nex2[20010],v2[20010];
void AddEdg2(int U,int V){
	v2[++e2]=V;
	nex2[e2]=firs2[U];
	firs2[U]=e2;
}
int A,B,n,m,du[5010],du2[5010],ans1,ans2,ans3;
int main(){
	int x,y;
//	freopen("a.in","r",stdin);
	scanf("%d%d%d%d",&A,&B,&n,&m);
	for(int i=1;i<=m;++i){
		scanf("%d%d",&x,&y); ++x; ++y;
		AddEdge(x,y);
		AddEdg2(y,x);
		++du[y];
		++du2[x];
	}
	for(int i=1;i<=n;++i){
		S[i].set(i);
		if(!du2[i]){
			q.push(i);
		}
	}
	while(!q.empty()){
		int U=q.front();
		for(int i=firs2[U];i;i=nex2[i]){
			S[v2[i]]|=S[U];
			--du2[v2[i]];
			if(!du2[v2[i]]){
				q.push(v2[i]);
			}
		}
		q.pop();
	}
	for(int i=1;i<=n;++i){
		siz[i]=S[i].count();
		S[i].reset();
		S[i].set(i);
		if(!du[i]){
			q.push(i);
		}
	}
	while(!q.empty()){
		int U=q.front();
		for(int i=first[U];i;i=next[i]){
			S[v[i]]|=S[U];
			--du[v[i]];
			if(!du[v[i]]){
				q.push(v[i]);
			}
		}
		q.pop();
	}
	for(int i=1;i<=n;++i){
		si2[i]=S[i].count();
	}
	for(int i=1;i<=n;++i){
		if(siz[i]>n-A){
			++ans1;
		}
	}
	for(int i=1;i<=n;++i){
		if(siz[i]>n-B){
			++ans2;
		}
	}
	for(int i=1;i<=n;++i){
		if(si2[i]>B){
			++ans3;
		}
	}
	printf("%d\n%d\n%d\n",ans1,ans2,ans3);
	return 0;
}

【拓撲排序】【bitset】Gym - 101128A - Promotions