zoukankan      html  css  js  c++  java
  • 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
    ",ans1,ans-1);
        return 0;
    }
    View Code
  • 相关阅读:
    Git 创建仓库并拉取代码
    Linux export 命令
    Linux ps 命令
    Linux sed 命令
    Linux find 命令
    Linux chmod 命令
    Linux chgrp 命令
    解除/配置 linux/nginx 的 tcp 连接(nginx配置文件日常配置推荐)
    更改Ubuntu的apt源
    anaconda 各版本的下载地址
  • 原文地址:https://www.cnblogs.com/ihopenot/p/6422540.html
Copyright © 2011-2022 走看看