• BZOJ3832: [Poi2014]Rally(拓扑排序 堆)


    题意

    题目链接

    Sol

    最直观的思路是求出删除每个点后的最长路,我们考虑这玩意儿怎么求

    (f[i])表示以(i)结尾的最长路长度,(g[i])表示以(i)开始的最长路长度

    根据DAG的性质,显然我们删除一个点后,整个集合会被分成两部分:拓扑序小于/大于当前点

    那么此时的最长路一定可以通过计算连接着两个集合的边((u, v))(f(u) + f(v) +1)得到

    这样的话我们可以直接维护边集,在统计每个点的答案的时候首先删掉入边的贡献统计答案,统计完后再加入出边的贡献

    显然线段树可以维护,其实堆也可以维护,具体见代码(抄袭自yyb大佬)

    #include<bits/stdc++.h>
    #define chmax(x, y) (x = (x > y ? x : y))
    #define chmin(x, y) (x = (x < y ? x : y))
    using namespace std;
    const int MAXN = 1e6 + 10, INF = 1e9 + 10;
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int N, M, a1 = INF, a2;
    class MyPriorityQueue {
        public: 
            priority_queue<int> q1, q2;
            void push(int x) {
                q1.push(x);
            }
            int pop(int x) {
                q2.push(x);
            }
            bool empty() {
                while(!q2.empty() && (q1.top() == q2.top())) q1.pop(), q2.pop();
                return q1.size() == 0;
            }
            int top() {
                return empty() ? INF : q1.top();
            }   
    };
    MyPriorityQueue Q;
    struct Graph {
        vector<int> v[MAXN];
        int f[MAXN], inder[MAXN], id[MAXN], tot;
        Graph() {
            tot = 0;
        }
        void AddEdge(int x, int y) {
            v[x].push_back(y); inder[y]++;
        }
        void Topsort() {
            queue<int> q;
            for(int i = 1; i <= N; i++) if(!inder[i]) q.push(i);
            while(!q.empty()) {
                int p = q.front(); q.pop(); id[++tot] = p;
                for(int i = 0; i < v[p].size(); i++) {
                    int to = v[p][i]; chmax(f[to], f[p] + 1);
                    if(!(--inder[to])) q.push(to);
                }
            }
        }
    };
    Graph Gs, Gt;
    int main() {
        N = read(); M = read();
        for(int i = 1; i <= M; i++) {
            int x = read(), y = read();
            Gs.AddEdge(x, y); Gt.AddEdge(y, x);
        }
        Gs.Topsort(); Gt.Topsort();
        for(int i = 1; i <= N; i++) Q.push(Gt.f[i]);
        for(int t = 1; t <= N; t++) {
            int x = Gs.id[t]; Q.pop(Gt.f[x]);
            for(int i = 0; i < Gt.v[x].size(); i++) {
                int to = Gt.v[x][i];
                Q.pop(Gs.f[to] + Gt.f[x] + 1);
            }
            int now = Q.top(); Q.push(Gs.f[x]);
            if(now < a1) a1 = now, a2 = x;
            for(int i = 0; i < Gs.v[x].size(); i++) {
                int to = Gs.v[x][i];
                Q.push(Gs.f[x] + Gt.f[to] + 1);
            }
        }
        printf("%d %d
    ", a2, a1);
        return 0;
    }
    
  • 相关阅读:
    Java 端口转发
    Tomcat笔记
    RocketMQ开启ACL后客户端连接报Algorithm HmacSHA1 not available的解决方式
    RSA签名与验签
    小米9升级MIUI11
    【转】linux awk命令详解
    进程和线程
    Jenkins笔记
    【转】Jenkins启动、停止脚本
    UiAutomator源码分析
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/10197269.html
Copyright © 2020-2023  润新知