4484: [Jsoi2015]最小表示

来源:互联网 发布:nba2kol挂机软件 编辑:程序博客网 时间:2024/06/06 01:21
讲一句废话。边x->y能被删掉当且仅当x能走过其他路到y。
先进行拓扑排序,然后按拓扑序的逆序加点,这样可以保证每次加进去的点都没有入度。
记当前枚到的点为x。然后对x能到的所有点按到出度为0的点的最长路排序,从大到小枚举,记为y。用bitset维护一个点能到达哪些点。如果y到的点x都已经能到了,那就把x->y删掉。
#include<cstdio>#include<cstring>#include<iostream>#include<vector>#include<algorithm>#include<set>#include<bitset>using namespace std;#define rep(i,j,k) for(i=j;i<=k;++i)#define per(i,j,k) for(i=j;i>=k;--i)#define G getchar()#define LL long long#define pll pair<int,int>#define mkp make_pair#define X first#define Y secondconst int N=30005;int n,m,ans;vector<int>he[N];int q[N],in[N];bitset<30001>bit[N];int d[N];void read(int &x){char ch=G;while(ch<48||ch>57)ch=G;for(x=0;ch>47&&ch<58;ch=G)x=x*10+ch-48;}void BFS(){int Ft=1,Rr=1,i,u,v;vector<int>::iterator ii;rep(i,1,n)if(!in[i])q[Rr++]=i;while(Ft<Rr)for(ii=he[u=q[Ft++]].begin();ii!=he[u].end();++ii)if(!(--in[v=*ii]))q[Rr++]=v;}bool cmp(int x,int y){return d[x]>d[y];}int main(){int x,y,i;vector<int>::iterator ii;read(n);read(m);while(m--){read(x);read(y);he[x].push_back(y);++in[y];}BFS();per(i,n,1){x=q[i];bit[x].set(x);sort(he[x].begin(),he[x].end(),cmp);for(ii=he[x].begin();ii!=he[x].end();++ii){d[x]=max(d[x],d[y=*ii]+1);if((bit[x]&bit[y])==bit[y])++ans;else bit[x]|=bit[y];}}printf("%d\n",ans);return 0;}