BZOJ4484 JSOI2015最小表示(拓扑排序+bitset)
考虑在每个点的出边中删除哪些。如果其出边所指向的点中存在某点能到达另一点,那么显然指向被到达点的边是没有用的。于是拓扑排序逆序处理,按拓扑序枚举出边,bitset维护可达点集合即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<bitset> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 30010 #define M 100010 int n,m,p[N],id[N],degree[N],q[N],v[N],t,ans; bitset<N> a[N],b; struct data{int to,nxt; }edge[M]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void topsort() { int head=0,tail=0;for (int i=1;i<=n;i++) if (!degree[i]) q[++tail]=i,id[i]=tail; while (tail<n) { int x=q[++head]; for (int i=p[x];i;i=edge[i].nxt) { degree[edge[i].to]--; if (!degree[edge[i].to]) q[++tail]=edge[i].to,id[edge[i].to]=tail; } } } bool cmp(const int&a,const int&b) { return id[a]<id[b]; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4484.in","r",stdin); freopen("bzoj4484.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); for (int i=1;i<=m;i++) { int x=read(),y=read(); addedge(x,y);degree[y]++; } topsort(); for (int i=n;i>=1;i--) { int x=q[i],t=0;a[x][x]=1; for (int j=p[x];j;j=edge[j].nxt) v[++t]=edge[j].to; sort(v+1,v+t+1,cmp); for (int j=1;j<=t;j++) if (a[x][v[j]]) ans++; else a[x]|=a[v[j]]; } cout<<ans; return 0; }