BZOJ3832Rally题解

一道思维神题....

我们像网络流一样加入原点S,与汇点T

用f[i]表示原点到i的最长路,用g[i]表示i到汇点的最长路

f数组与g数组都可以dp求出来的

接下来考虑如何通过这些信息来维护删除某个点的最长路

用拓扑序来删点

我们先将所有g数组加入一个集合中,

每次删点是就先将所有该点的入边的点的f[i]+g[x]从集合中删掉

然后此时集合中最大值就是删除这个点的最优解

然后再将每个点的出边i的f[x]+g[i]加入集合中

可以发现这个集合可以用堆来维护

# include<iostream>
# include<cstdio>
# include<cmath>
# include<cstring>
# include<algorithm>
# include<queue>
using namespace std;
const int mn = 500005;
struct Grap{
    struct edge{int to,next;};
    edge e[mn*2];
    int head[mn],edge_max;
    void add(int x,int y)
    {
        e[++edge_max].to=y;
        e[edge_max].next=head[x];
        head[x]=edge_max;
    }
}A,B;
int deg[mn*2],n,m,a[mn*2];
int f[mn*2],g[mn*2];
void topolpgy()
{
    int tail=1,head=0;
    for(int i=1;i<=n;i++)
        if(!deg[i]) a[++head]=i;
    //printf("%d %d\n",tail,head);
    while(tail<=head)
    {
        int u=a[tail];
        tail++;
        for(int i=A.head[u];i;i=A.e[i].next)
        {
            deg[A.e[i].to]--;
            if(!deg[A.e[i].to]) a[++head]=A.e[i].to;
        }
    }
}
struct Heap{
    int heap[mn*2],mark[mn*2],top;
    void ins(int x)
    {
        if(mark[x])
        {
            --mark[x];
            return ;
        }
        heap[++top]=x;
        int t=top;
        while(t>1)
        {
            if(heap[t]>heap[t>>1])
                swap(heap[t],heap[t>>1]),t>>=1;
            else
                break;
        }
    }
    void del(int x)
    {
        mark[x]++;
    }
    void Pop()
    {
        heap[1]=heap[top--];
        int t=2;
        while(t<=top)
        {
            if( t<top && heap[t+1]>heap[t] )
                t++;
            if(heap[t]>heap[t>>1])
                swap(heap[t],heap[t>>1]),t<<=1;
            else
                break;
        }
    }
    int Top()
    {
        while(mark[heap[1]])
            mark[heap[1]]--,Pop();
        return heap[1];
    }
}T;
int main()
{
    int x,y;
    A.edge_max=0,B.edge_max=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        A.add(x,y),B.add(y,x);
        deg[y]++;
    }
    topolpgy();
    /*for(int i=1;i<=n;i++)
        printf("%d ",a[i]);*/
    int ans=0,ans_len=0x3f3f3f3f;
    for(int i=1;i<=n;i++)
    {
        int u=a[i];
        f[u]=max(f[u],1);
        for(int j=A.head[u];j;j=A.e[j].next)
            f[A.e[j].to]=max(f[A.e[j].to],f[u]+1);
    }
    for(int i=n;i>=1;i--)
    {
        int u=a[i];
        g[u]=max(g[u],1);
        for(int j=A.head[u];j;j=A.e[j].next)
            g[u]=max(g[u],g[A.e[j].to]+1);
    }
    /*for(int i=1;i<=n;i++)
        printf("%d:%d %d\n",i,f[i],g[i]);*/
    for(int i=1;i<=n;i++)
        T.ins(g[i]);
    T.ins(0);
    for(int i=1;i<=n;i++)
    {
        int u=a[i];
        for(int j=B.head[u];j;j=B.e[j].next)
        {
            T.del(f[B.e[j].to]+g[u]);
           //printf("%d ",f[B.e[j].to]+g[u]);
        }
        //printf("\n");
        T.del(g[u]);
        if(T.Top()<ans_len)
        {
            ans_len=T.Top(),ans=u;
            //printf("%d ",T.Top());
        }
        for(int j=A.head[u];j;j=A.e[j].next)
        {
            T.ins(f[u]+g[A.e[j].to]);
            //printf("%d ",f[u]+g[B.e[j].to]);
        }
        T.ins(f[u]);
        //printf("%d\n",ans_len-1);
    }
    printf("%d %d",ans,ans_len-1);
    return 0;
}

 

posted @ 2018-09-07 18:58  logeadd  阅读(163)  评论(0编辑  收藏  举报