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;
}

 

posted @ 2018-10-31 10:58  Gloid  阅读(201)  评论(0编辑  收藏  举报