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;
}

 

posted @ 2019-02-01 11:44  MJT12044  阅读(184)  评论(0编辑  收藏  举报