Bzoj3832--Poi2014Rally

题意 : 

给定一个DAG,问去掉一个点后最长路径长度最短是多少。

 

---------------此后一千里--------------------------

 

 

 

 

 

 

 

 

 

 

先%一发

神奇的思路

我们考虑将整个图topo排序一下,处理出到每个点的最长路径长度f[i]和每个点出发的最长路径长度g[i]

那么对于图上的一条可能最长路径,我们就可以表示成f[i]+g[j],然后我们可以把这个值赋给i->j的边上

问题就变成了去掉一个点,原图割集的边权与割开部分边权的最大值

我们先假设所有点都在T集合里,那么割集是没有边的,我们只用管T集里的边权,就可以把所有点的g丢到堆里

我们如果删除一个点,我们可以把它从T集里删去,对T集边权影响是去掉这个点的g值,对割集影响是去掉这个点与S集连边的权值

恢复时把这个点丢到S集去,影响和删除差不多

我们怎么样方便的去维护上面这些东西呢?

可以按topo序去维护

因为如果乱丢的话,你丢掉的点可能会影响在T集里的点的g值,就会出错,而如果按topo序丢,可以保证你丢的这个点不会影响仍在T集里的点的g,而且可以保证直接连向这个点的点都在S集里,就可以方便地维护上面的信息了

至于为什么恢复时要丢到S集去,因为在S集里我们关心的是点的f值,你之后删除别的点对之前点的f值是没有影响的,而对g值有影响

代码 : 

#include<bits/stdc++.h>
using namespace std;

inline int Max(int a,int b) {return a>b?a:b;}
inline int Min(int a,int b) {return a<b?a:b;}

#define MAXN 500005

int n,m,ans=MAXN+5,ans1;
int head[MAXN][2],cnt,deg[MAXN][2];bool vis[MAXN][2];
struct Edge{
    int to,next;
}e[MAXN*4];
inline void insert(int a,int b,int p) {
    deg[a][p]++;
    e[++cnt].next=head[a][p];head[a][p]=cnt;e[cnt].to=b;
}
int f[MAXN],g[MAXN],tp[MAXN][2];

void topo(int v,int p) {
    tp[++tp[0][p]][p]=v;vis[v][p]=1;
    for(int i=head[v][p^1];i;i=e[i].next) 
        if(--deg[e[i].to][p]==0&&!vis[e[i].to][p]) topo(e[i].to,p); 
}

priority_queue<int> q,d;

int main() {
    scanf("%d%d",&n,&m);
    for(int a,b,i=1;i<=m;i++) {
        scanf("%d%d",&a,&b);
        insert(a,b,1);insert(b,a,0);
    }
    for(int i=1;i<=n;i++) {
        if(!deg[i][0]&&!vis[i][0]) topo(i,0);
        if(!deg[i][1]&&!vis[i][1]) topo(i,1);
    }
    for(int i=1;i<=n;i++) {
        int a=tp[i][1],b=tp[i][0];
        for(int j=head[a][1];j;j=e[j].next) 
            g[a]=Max(g[a],g[e[j].to]);
        for(int j=head[b][0];j;j=e[j].next) f[b]=Max(f[b],f[e[j].to]);
        g[a]++;f[b]++;
    }
    for(int i=1;i<=n;i++) q.push(g[i]);
    for(int i=1;i<=n;i++) {
        int k=tp[i][0];
        for(int j=head[k][0];j;j=e[j].next) d.push(f[e[j].to]+g[k]);
        d.push(g[k]);
        while(!d.empty()&&!q.empty()&&d.top()==q.top()) q.pop(),d.pop();
        if(q.top()<ans) {ans=q.top();ans1=k;}
        for(int j=head[k][1];j;j=e[j].next) q.push(f[k]+g[e[j].to]);
        q.push(f[k]);
    }
    printf("%d %d\n",ans1,ans-1);
    return 0;
}
View Code

 

posted @ 2017-02-21 09:31  ihopenot  阅读(274)  评论(0编辑  收藏  举报