bzoj 4484 [Jsoi2015] 最小表示 solution

来源:互联网 发布:淘宝文案策划岗位职责 编辑:程序博客网 时间:2024/06/05 04:44

题意:给定一个N个点,M条边的有向无环图,问:最多删去几条边,使得原图的连通性不变?


分析:将原图拓扑序处理出来,按照从后往前的顺序枚举每一个点。对于每一个点,求出它所指向的点到汇点距离从大到小排序后的一个序列。枚举序列中的点,若一个点已经能被访问到,则删除的边答案增加,可以用bitset维护。


代码:

#include<cstdio>
#include<bitset>
#include<algorithm>
using namespace std;

#define to e[i].v
#define dep(i,a,b) for (int i=a;i>=b;--i)
#define rep(i,a,b) for (int i=a;i<=b;++i)
#define inf 1234567890
#define N 30005
#define M 100005

int n,m,id,ru[N],q[N],head[N],l,r,cnt,dist[N],ans;
bitset<N> bit[N];

struct Node{
    int next,v;
}e[M];

struct node{
    int u,v;
}a[N];

int max(int a,int b) {return a>b? a:b;}
int min(int a,int b) {return a>b? b:a;}
void swap(int &a,int &b) {int t=a;a=b;b=t;}

int read()
{
    int x=0,f=1;char ch=getchar();
    for (;ch>'9'||ch<'0';ch=getchar()) if (ch=='-') f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x*f;
}

void add(int u,int v) {e[id].v=v; e[id].next=head[u]; head[u]=id++;}

bool cmp(node a,node b) {return a.v>b.v;}

int main()
{
    n=read(); m=read(); id=1;
    rep(i,1,m)
    {
        int u=read(),v=read();
        add(u,v); ++ru[v];
    }
    l=0; rep(i,1,n) if (!ru[i]) q[++r]=i;
    for (;l^r;)
    {
        int u=q[++l];
        for (int i=head[u];i;i=e[i].next) if (!(--ru[to])) q[++r]=to;
    }
    dep(I,n,1)
    {
        int u=q[I];cnt=0;bit[u][u]=1;dist[u]=1;
        for (int i=head[u];i;i=e[i].next)
        {
            a[++cnt].u=to; a[cnt].v=dist[to];
            dist[u]=max(dist[u],dist[to]+1);
        }
        sort(a+1,a+cnt+1,cmp);
        rep(i,1,cnt)
        {
            if (bit[u][a[i].u]) ++ans;
            bit[u]|=bit[a[i].u];
        }
    }
    printf("%d",ans);
    return 0;
}