给你一张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;
}