• [POI 2014]RAJ-Rally


    Description

    题库链接

    给定一个 (N) 个点 (M) 条边的有向无环图,每条边长度都是 (1)。请找到一个点,使得删掉这个点后剩余的图中的最长路径最短。

    (1leq Nleq 500 000,1leq Mleq 1 000 000)

    Solution

    比较神...

    值得注意的是,对于一张 ( ext{DAG}) 的拓扑序,任意从中截断那么前一部分以及后一部分的点都是连续的。

    考虑按拓扑序来做,我们需要维护的就只是左边一部分内的最长路,以及右边一部分内的最长路。

    除此之外还要维护经过被“割开”边的最长路。

    对于删除一个点,我们需要做的就是将“割边”转移,维护上述需要维护的信息。

    可以用可删除的堆来实现,不过考虑到空间的花销,用权值线段树可以实现同样的功能。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 500000+5, inf = ~0u>>1;
    
    int n, m, u, v, c1[N], c2[N], q[N];
    struct graph {
        struct tt {int to, next; }edge[N<<1];
        int path[N], top, in[N];
        void add(int u, int v) {edge[++top] = (tt){v, path[u]}, path[u] = top, ++in[v]; }
        void topsort(int* c, int flag) {
            queue<int>Q; int cnt = 0;
            for (int i = 1; i <= n; i++) if (!in[i]) Q.push(i);
            while (!Q.empty()) {
                int u = Q.front(); Q.pop(); if (flag) q[++cnt] = u;
                for (int i = path[u]; i; i = edge[i].next) {
                    --in[edge[i].to]; c[edge[i].to] = max(c[edge[i].to], c[u]+1);
                    if (in[edge[i].to] == 0) Q.push(edge[i].to);
                }
            }
        }
    }g1, g2;
    struct Segment_tree {
    #define lr(o) (o<<1)
    #define rr(o) (o<<1|1)
        int mx[N<<2], cnt[N<<2];
        Segment_tree() {memset(mx, -1, sizeof(mx)); }
        void modify(int o, int l, int r, int loc, int key) {
            if (l == r) {
                cnt[o] += key;
                if (cnt[o] == 1) mx[o] = l;
                else if (cnt[o] == 0) mx[o] = -1;
                return;
            }
            int mid = (l+r)>>1;
            if (loc <= mid) modify(lr(o), l, mid, loc, key);
            else modify(rr(o), mid+1, r, loc, key);
            mx[o] = max(mx[lr(o)], mx[rr(o)]);
        }
    }T;
    
    void work() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++) {
            scanf("%d%d", &u, &v); g1.add(u, v), g2.add(v, u);
        }
        g1.topsort(c1, 1), g2.topsort(c2, 0);
        int ans = inf, pos;
        for (int i = 1; i <= n; i++) T.modify(1, 0, n, c2[i], 1);
        for (int id = 1; id <= n; id++) {
            int u = q[id];
            for (int i = g2.path[u]; i; i = g2.edge[i].next)
                T.modify(1, 0, n, c2[u]+c1[g2.edge[i].to]+1, -1);
            T.modify(1, 0, n, c2[u], -1);
            if (T.mx[1] < ans) ans = T.mx[1], pos = u;
            for (int i = g1.path[u]; i; i = g1.edge[i].next)
                T.modify(1, 0, n, c1[u]+c2[g1.edge[i].to]+1, 1);
            T.modify(1, 0, n, c1[u], 1);
        }
        printf("%d %d
    ", pos, ans);
    }
    int main() {work(); return 0; } 
  • 相关阅读:
    最全!即学即会 Serverless Devs 基础入门(上)
    一站式智能运维解决方案,企业系统的隐形守护者
    Serverless JOB | 传统任务新变革
    好的 MySQL 兼容性可以做到什么程度? PolarDBX 如何做生态兼容
    Apsara Stack 技术百科 | 如何「场景化」的企业上云
    事务、全局索引、透明分布式,再见,分区健!
    IT人才能嗑到的这对CP,甜!
    腾讯云:最简单CentOS7下安装GUI图形界面(最新)
    Navicat连接不上Mysql 8问题解决方案
    【JS】验证表单是否空白验证
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/9196142.html
Copyright © 2020-2023  润新知