BZOJ1576 USACO 2009 Jan Gold 3.Safe Travel Solution

题意:一个无向图,保证点1到其余点的最短路径存在且唯一。现在对于点2~n,询问若删去点1到这个点最短路上的最后一条边,此时点1到这个点新的最短路长度是多少。若不存在路径输出-1.


Solution:

首先跑一遍源点为1的单源最短路,随后建立以1为根的最短路径树。在最短路径树中,一个点的父亲节点是1到这个点的最短路上的倒数第二个点。

那么对于每个询问,事实上是断掉树上这个点和其父亲之间的边,求解新的最短路。

此时1和这个点不联通了,显然我们必须通过非树边才可能到达这个点。

显然能够证明若存在一条路径,那么当其最短时经过的非树边至多只有一条。

因此我们考虑每一条非树边对某些点答案的影响。

设一条非树边(x,y),若x不在以z为根的子树中,且y在以z为根的子树中,那么若z与z的父亲之间的边断掉,我们可以通过边(x,y)来到达z.那么我们经过的路径长度呢?

不妨设点1到点i的最短路长度为dis[i],则路径长度为dis[x]+len(x,y)+dis[y]-dis[z].不妨设为g(x,y)-dis[z].

因此,对于每个点z,我们只需维护出min{g(x,y)}.最终将答案减去dis[z]即可。

那么对于一条边(x,y)它能更新哪些点呢?

通过画图我们发现,它能更新路径(x,y)除了lca(x,y)之外的所有点。

那么利用树链剖分维护即可。

总的时间复杂度为O(mlogn).

虽然最短路不是瓶颈,但却很卡常数。用了SLF-spfa才勉强卡过去。


Code:

//SLF-Spfa
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
 
inline int getc() {
    static const int L = 1 << 15;
    static char buf[L], *S = buf, *T = buf;
    if (S == T) {
        T = (S = buf) + fread(buf, 1, L, stdin);
        if (S == T)
            return EOF;
    }
    return *S++;
}
inline int getint() {
    int c;
    while(!isdigit(c = getc()));
    int tmp = c - '0';
    while(isdigit(c = getc()))
        tmp = (tmp << 1) + (tmp << 3) + c - '0';
    return tmp;
}
 
#define INF 0x3f3f3f3f
 
deque<int> q;
 
#define N 100010
#define M 200010
int n, m;
struct Graph {
    int head[N], next[M << 1], end[M << 1], len[M << 1], ind;
    int dis[N], ld[N];
    bool inq[N];
     
    void reset() {
        ind = 0;
        memset(head, -1, sizeof(head));
    }
    void addedge(int a, int b, int _len) {
        int q = ind++;
        next[q] = head[a];
        head[a] = q;
        end[q] = b;
        len[q] = _len;
    }
    void make(int a, int b, int _len) {
        addedge(a, b, _len);
        addedge(b, a, _len);
    }
    void spfa(int S) {
        memset(dis, 0x3f, sizeof(dis));
        dis[S] = 0;
        memset(inq, 0, sizeof(inq));
        inq[S] = 1;
        q.push_back(S);
        int i, j;
        while(!q.empty()) {
            i = q.front();
            q.pop_front();
            inq[i] = 0;
            for(j = head[i]; j != -1; j = next[j]) {
                if (dis[end[j]] > dis[i] + len[j]) {
                    ld[end[j]] = i;
                    dis[end[j]] = dis[i] + len[j];
                    if (!inq[end[j]]) {
                        inq[end[j]] = 1;
                        if (!q.empty() && dis[end[j]] < dis[q.front()])
                            q.push_front(end[j]);
                        else
                            q.push_back(end[j]);
                    }
                }
            }
        }
    }
}G;
 
#define l(x) S[x].l
#define r(x) S[x].r
#define Min(x) S[x].Min
struct Node {
    int l, r, Min;
}S[N << 2];
int ind;
int build(int dl, int dr) {
    int q = ++ind;
    Min(q) = INF;
    if (dl == dr)
        return q;
    int mid = (dl + dr) >> 1;
    l(q) = build(dl, mid);
    r(q) = build(mid + 1, dr);
    return q;
}
void modify(int q, int dl, int dr, int tl, int tr, int add) {
    Min(l(q)) = min(Min(l(q)), Min(q));
    Min(r(q)) = min(Min(r(q)), Min(q));
    if (tl <= dl && dr <= tr) {
        Min(q) = min(Min(q), add);
        return;
    }
    int mid = (dl + dr) >> 1;
    if (tl > mid)
        modify(r(q), mid + 1, dr, tl, tr, add);
    else if (tr <= mid)
        modify(l(q), dl, mid, tl, tr, add);
    else {
        modify(l(q), dl, mid, tl, mid, add);
        modify(r(q), mid + 1, dr, mid + 1, tr, add);
    }
}
int ask(int q, int dl, int dr, int ins) {
    Min(l(q)) = min(Min(l(q)), Min(q));
    Min(r(q)) = min(Min(r(q)), Min(q));
    if (dl == dr)
        return Min(q);
    int mid = (dl + dr) >> 1;
    if (ins <= mid)
        return ask(l(q), dl, mid, ins);
    else
        return ask(r(q), mid + 1, dr, ins);
}
 
int head[N], next[N], end[N];
void addedge(int a, int b) {
    static int q = 1;
    end[q] = b;
    next[q] = head[a];
    head[a] = q++;
}
int size[N], weighson[N], depth[N], pa[N][21];
void dfs_build(int x) {
    size[x] = 1;
    int Maxsize = 0;
    for(int j = head[x]; j; j = next[j]) {
        depth[end[j]] = depth[x] + 1;
        pa[end[j]][0] = x;
        dfs_build(end[j]);
        if (size[end[j]] > Maxsize)
            Maxsize = size[end[j]], weighson[x] = end[j];
        size[x] += size[end[j]];
    }
}
int top[N], id_p[N], p_id[N], id;
void dfs_create(int x, int Top) {
    top[x] = Top;
    p_id[x] = ++id;
    id_p[id] = x;
    if (weighson[x])
        dfs_create(weighson[x], Top);
    for(int j = head[x]; j; j = next[j])
        if (end[j] != weighson[x])
            dfs_create(end[j], end[j]);
}
 
int Lca(int x, int y) {
    if (depth[x] < depth[y])
        swap(x, y);
    int i;
    for(i = 20; i >= 0; --i)
        if (depth[pa[x][i]] >= depth[y])
            x = pa[x][i];
    if (x == y)
        return x;
    for(i = 20; i >= 0; --i)
        if (pa[x][i] != pa[y][i])
            x = pa[x][i], y = pa[y][i];
    return pa[x][0];
}
int low(int x, int y) {
    for(int i = 20; i >= 0; --i)
        if (depth[pa[x][i]] > depth[y])
            x = pa[x][i];
    return x;
}
 
struct Edge {
    int from, to, len;
    Edge(int _from = 0, int _to = 0, int _len = 0):from(_from),to(_to),len(_len){}
}E[M];
 
void update(int x, int y, int add) {
    while(top[x] != top[y]) {
        if (depth[top[x]] < depth[top[y]])
            swap(x, y);
        modify(1, 1, n, p_id[top[x]], p_id[x], add);
        x = pa[top[x]][0];
    }
    if (depth[x] < depth[y])
        swap(x, y);
    modify(1, 1, n, p_id[y], p_id[x], add);
}
 
int main() {
    n = getint();
    m = getint();
     
    int a, b, x, y, z, t;
    register int i, j;
     
    G.reset();
    for(i = 1; i <= m; ++i) {
        a = getint();
        b = getint();
        x = getint();
        G.make(a, b, x);
        E[i] = Edge(a, b, x);
    }
     
    G.spfa(1);
     
    for(i = 2; i <= n; ++i)
        addedge(G.ld[i], i);
     
    depth[1] = 1;
    dfs_build(1);
    dfs_create(1, 1);
    build(1, n);
     
    for(j = 1; j <= 20; ++j)
        for(i = 1; i <= n; ++i)
            pa[i][j] = pa[pa[i][j - 1]][j - 1];
     
    for(i = 1; i <= m; ++i) {
        x = E[i].from;
        y = E[i].to;
        if (depth[x] < depth[y])
            swap(x, y);
        if (pa[x][0] == y)
            continue;
         
        z = Lca(x, y);
         
        t = low(x, z);
        if (t != z)
            update(x, t, G.dis[x] + G.dis[y] + E[i].len);
        t = low(y, z);
        if (t != z)
            update(y, t, G.dis[x] + G.dis[y] + E[i].len);
    }
     
    int res;
    for(i = 2; i <= n; ++i) {
        res = ask(1, 1, n, p_id[i]);
        printf("%d\n", res == INF ? -1 : res - G.dis[i]);
    }
     
    return 0;
}


你可能感兴趣的:(BZOJ1576 USACO 2009 Jan Gold 3.Safe Travel Solution)