• 【10.27校内测试】【可删堆+拓排】


    Solution

    有向图要找最长路径的话,可以想到拓扑序转移。正反跑两边处理出每个点离起点和终点的最大值。访问每条边就能统计出经过每条边最长路径的长度。

    问题是怎么统计出删除每个点的影响?

    拓扑排序后,可以发现,删除层数靠后的点会对前面产生影响,因为此时想统计前面的边存在的最长路就不能判掉经过这个点的路径,所以只能按拓扑序从前往后删点。

    这里直接说做法吧,维护一个大根堆,储存当前枚举到的最长路径,首先把每个点离终点的最大值推入堆中。每枚举删除一个点,就把它对前面点有影响的路径删掉,更新答案后再把它对后面的路径加入堆中,做完所有点即可。

    但是堆不能直接实现制定元素删除操作,所以要用可删堆QAQ

    其实就是两个堆,一个维护当前堆,一个维护待删除的元素,每次删除就往第二个堆中加入元素,实际操作是在取出过程中实现的,如果当前两个堆顶元素相同时,就删除两个堆顶即可。

    %%%$jzy$大佬码风新奇,我等一般人只能仰望%%%

    Code

    #include<bits/stdc++.h>
    #define RG register
    using namespace std;
    inline char nc()
    {
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline void read(int &x) {
        x = 0; int t = 1; char ch = nc();
        while(ch > '9' || ch < '0') { if(ch == '-')    t = -1; ch = nc(); }
        while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = nc(); }
        x *= t;
    }
    
    struct Node {
        int v, nex;
    } Edge[500005], Edge_rz[500005];
    
    int stot_rz = 0, h_rz[100005], stot, h[100005];
    void add(int u, int v) {
        Edge[++stot] = (Node) {v, h[u]};
        h[u] = stot;
        Edge_rz[++stot_rz] = (Node) {u, h_rz[v]};
        h_rz[v] = stot_rz;
    }
    
    class Heap {
        private:
            priority_queue < int > q1;
            priority_queue < int > q2;
        public:
            inline void init() {
                while(!q1.empty())    q1.pop();
                while(!q2.empty())    q2.pop();
            }
            inline void push(int x) {
                q1.push(x);
            }
            inline void del(int x) {
                q2.push(x);
            }
            inline int top() {
                while(!q2.empty() && q1.top() == q2.top()) {
                    q1.pop();    q2.pop();
                }
                return q1.top();
            }
    } Q;
    
    int in[100005], q[100005], st[100005], ed[100005], ans, id, n, m;
    int main() {
        freopen("johnny.in", "r", stdin);
        freopen("johnny.out", "w", stdout);
        int T;
        read(T);
        while(T --) {
            memset(h, 0, sizeof(h));
            memset(h_rz, 0, sizeof(h_rz));
            stot = 0, stot_rz = 0; int t = 0, hi = 1;
            memset(q, 0, sizeof(q));
            memset(in, 0, sizeof(in));
            memset(st, 0, sizeof(st));
            memset(ed, 0, sizeof(ed));
            ans = 0x3f3f3f3f, id = 0;
            Q.init();
            read(n);    read(m);
            while(m --) {
                int u, v;
                read(u);    read(v);
                add(u, v);
                in[v] ++;
            }
            for(int i = 1; i <= n; i ++)
                if(!in[i])    q[++t] = i;
            while(hi <= t) {
                int u = q[hi ++];
                for(RG int i = h[u]; i; i = Edge[i].nex) {
                    int v = Edge[i].v;
                    if((-- in[v]) == 0)    q[++t] = v;
                }
            }
            for(RG int i = 1; i <= n; i ++) {
                int u = q[i];
                for(RG int j = h[u]; j; j = Edge[j].nex) {
                    int v = Edge[j].v;
                    st[v] = max(st[v], st[u] + 1);
                }
            }
            for(RG int i = n; i >= 1; i --) {
                int u = q[i];
                for(RG int j = h_rz[u]; j; j = Edge_rz[j].nex) {
                    int v = Edge_rz[j].v;
                    ed[v] = max(ed[v], ed[u] + 1);
                }
            }
            for(int i = 1; i <= n; i ++)    Q.push(ed[i]);
            for(RG int i = 1; i <= n; i ++) {
                int u = q[i];
                for(int j = h_rz[u]; j; j = Edge_rz[j].nex) {
                    int v = Edge_rz[j].v;
                    Q.del(st[v] + ed[u] + 1);
                }
                Q.del(ed[u]);
                int now = Q.top();
                if(now < ans)    ans = now, id = u;
                else if(now == ans)    id = min(id, u);
                for(RG int i = h[u]; i; i = Edge[i].nex) {
                    int v = Edge[i].v;
                    Q.push(st[u] + ed[v] + 1);
                }
                Q.push(st[u]);
            }
            printf("%d %d
    ", id, ans);
        }
        return 0;
    }
  • 相关阅读:
    Perl 基础笔记: 使用 cpanm 安装 Perl 模块
    修改CPAN安装源
    JQUERY实现点击INPUT使光标移动到最后或指定位置
    新手入门Underscore.js 中文(template)
    深入浅出C/C++中的正则表达式库
    [libxml2]_[XML处理]_[使用libxml2的xpath特性修改xml文件内容]
    Mysql事务的隔离级别
    HBase基础知识摘要
    java如何实现一个Future
    遇到过的问题整理-大量页面监控问题
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9866668.html
Copyright © 2020-2023  润新知