zoukankan      html  css  js  c++  java
  • 3832: [Poi2014]Rally

    3832: [Poi2014]Rally

    链接

    分析:

      首先可以考虑删除掉一个点后,计算最长路。

      设$f[i]$表示从起点到i的最长路,$g[i]$表示从i出发到终点的最长路。那么经过一条边的最长路就是$f[u]+1+g[v]$。

      删除一个点x后,会使一些路径没了。考虑这些路径的特点。我们它比x拓扑序小的设为集合S,拓扑序大的设为T。

      1、如果以前的一条路径经过x,那么去掉x后,考虑如何去掉这些路径的影响。只需将x的入边删掉就行了。

      2、那么如何统计新的答案,并且新的路径不能经过x。此处是一个有意思的地方,统计所有起点在S,终点在T的所有边,会发现所有经过这些边的路径都不会经过x。(这些路径中一般是起代替x的作用的,但是存在一些边并没有代替x,但是对答案不影响)。

      那么做法就出来了:按照拓扑序删点,不断维护起点在S,终点在T的边,每条边权值为$f[u]+1+g[v]$,取最大值。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long LL;
    
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
    
    const int N = 500005;
    int g[N], f[N], T[N << 2], cnt[N << 2], q[N], n;
    
    struct Edge{
        int to[N << 1], nxt[N << 1], head[N], En, deg[N << 1];
        inline void add_edge(int u,int v) {
            ++En; to[En] = v, nxt[En] = head[u]; head[u] = En; deg[v] ++;
        }
    }Z, F;
    
    void solve() {
        int L = 1, R = 0;
        for (int i = 1; i <= n; ++i) if (F.deg[i] == 0) q[++R] = i;
        while (L <= R) {
            int u = q[L ++];
            for (int i = F.head[u]; i; i = F.nxt[i]) {
                int v = F.to[i];
                g[v] = max(g[v], g[u] + 1);
                if (!(--F.deg[v])) q[++R] = v;
            }
        }
        L = 1, R = 0;
        for (int i = 1; i <= n; ++i) if (Z.deg[i] == 0) q[++R] = i;
        while (L <= R) {
            int u = q[L ++];
            for (int i = Z.head[u]; i; i = Z.nxt[i]) {
                int v = Z.to[i];
                f[v] = max(f[v], f[u] + 1);
                if (!(--Z.deg[v])) q[++R] = v;
            }
        }
    }
    void update(int l,int r,int rt,int p,int v) {
        if (l == r) {
            cnt[rt] += v;
            if (cnt[rt] > 0) T[rt] = l;
            else T[rt] = -1, cnt[rt] = 0;
            return ;
        }
        int mid = (l + r) >> 1;
        if (p <= mid) update(l, mid, rt << 1, p, v);
        else update(mid + 1, r, rt << 1 | 1, p, v);
        T[rt] = max(T[rt << 1], T[rt << 1 | 1]);
    }
    int main() {
        n = read();int m = read();
        for (int i = 1; i <= m; ++i) {
            int x = read(), y = read();
            Z.add_edge(x, y);
            F.add_edge(y, x);
        }
        solve();
        int ans = 1e9, pt;
        for (int i = 1; i <= n; ++i) update(0, n, 1, g[i], 1);
        for (int i = 1; i <= n; ++i) {
            int x = q[i];
            for (int j = F.head[x]; j; j = F.nxt[j]) 
                update(0, n, 1, g[x] + f[F.to[j]] + 1, -1);
            update(0, n, 1, g[x], -1);
            if (T[1] < ans) ans = T[1], pt = x;
            for (int j = Z.head[x]; j; j = Z.nxt[j]) 
                update(0, n, 1, f[x] + g[Z.to[j]] + 1, 1);
            update(0, n, 1, f[x], 1);
        }
        cout << pt << " " << ans;
        return 0;
    }
  • 相关阅读:
    人工智能-实验一策略迭代和值迭代
    Lecture 3: Planning by Dynamic Programming
    Lecture 2: Markov Decision Processes
    Software Testing -- LAB02-Selenium上机实验
    数据结构-王道2017-第4章 树与二叉树-二叉树的遍历
    数据结构-王道2017-第4章 树与二叉树
    PHP-基础知识
    nginx的安装与配置
    在Linux上部署项目
    zk 命令
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10345311.html
Copyright © 2011-2022 走看看