bzoj2725: \[Violet 6\]故乡的梦 Dijkstra +线段树

bzoj2725: [Violet 6]故乡的梦

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

Sample Input

6 7
1 2 1
2 3 1
3 4 2
4 5 1
5 6 1
1 3 3
4 6 3
1 6
4
1 2
1 3
4 3
6 5

Sample Output

7
6
Infinity
7

分析

题意就是给你一张图,问去掉某条边的有源汇最短路长度。
这种题目肯定是先正着再倒着搞一边Dij,假设分别得到了两个数组 f , g
考虑我们如果维护出来了这个信息之后该怎么做。
首先搞定最间单的情况,就是对最短路没有影响的情况。
我们随便找到一条最短路,如果删掉的边不在这条路径上那么肯定不会影响。
这个时候我们就要考虑删掉的边在路径上的情况。
这里要用一个巧妙的思路,就是换一个方向考虑,我们注意这条最短路之外的边对于这条最短路删去某条边的影响。
对于某条边可以贡献的最短路就是 f u + w ( u , v ) + g v
(无向边变成有向边)。
这个时候我们考虑这个 f u + w ( u , v ) + g v 可以应用到哪种情况上。
假设某两个点间的路径集合是 W ( u , v )
我们假设
W ( S , u ) W ( S , T ) = W ( S , S u ) , W ( v , T ) W ( S , T ) = W ( T v , T )
那么不难发现,如果是 W ( S u , T v ) 中的任意一条边被删去之后,都可以用 f u + w ( u , v ) + g v 代替。
我们将 W ( S , T ) 上的边编号,用一个 D A G D P 搞出 S u , T v 最后每条边线段树取个 m i n 即可。

代码

码农题,加油。

/**************************************************************
    Problem: 2725
    User: 2014lvzelong
    Language: C++
    Result: Accepted
    Time:13900 ms
    Memory:36660 kb
****************************************************************/

#include<cstdio>
#include<cstring>
#include<algorithm>
const int Nt = 262143, N = 2e5 + 10;
int read() {
    char ch = getchar(); int x = 0, f = 1;
    for(;ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) - '0' + ch;
    return x * f;
}
struct data{int u; long long x;}T[Nt + 1 << 1];
data min(data a, data b) {return a.x < b.x ? a : b;}
int Pr[N], pre[N], to[N << 1], nxt[N << 1], w[N << 1], q[N], id[N];
int tp, n, U[N], V[N], W[N], a[N], fs[N], ft[N];
long long f[N], g[N], inf, t[N << 2], tg[N << 2], ans[N];
void add(int u, int v, int ww) {to[++tp] = v; nxt[tp] = pre[u]; pre[u] = tp; w[tp] = ww;}
void adds(int u, int v, int w) {add(u, v, w); add(v, u, w);}
void Up(int i, long long v) {for(T[i += Nt].x = v; i >>= 1; T[i] = min(T[i << 1], T[i << 1 | 1]));}
void Dij(int s, long long *D) {
    Pr[s] = 0; memset(T, 0x3f, sizeof(T));
    for(int i = 1;i <= n; ++i) T[i + Nt].u = i, D[i] = inf;
    for(Up(s, D[s] = 0); T[1].x != inf;) {
        int u = T[1].u; Up(u, inf);
        for(int i = pre[u]; i; i = nxt[i])
        if(D[to[i]] > D[u] + w[i])
            Pr[to[i]] = u, Up(to[i], D[to[i]] = D[u] + w[i]);
    }
}
void Find(int s, long long *D, int *Nx) {
    int L = 0, R; q[R = 1] = s; Nx[s] = s;
    for(int u = q[++L];L <= R; u = q[++L]) 
        for(int i = pre[u]; i; i = nxt[i]) 
        if(!id[to[i]] && !Nx[to[i]] && D[to[i]] == D[u] + w[i])
            q[++R] = to[i], Nx[to[i]] = s;
}
void Tag(int p, long long v) {t[p] = std::min(t[p], v); !tg[p] ? tg[p] = v : tg[p] = std::min(tg[p], v);}
void Upd(int p) {t[p] = std::min(t[p << 1], t[p << 1 | 1]);}
void Push(int p) {if(tg[p]) {Tag(p << 1, tg[p]); Tag(p << 1 | 1, tg[p]); tg[p] = 0;}}
void Upd(int p, int L, int R, int st, int ed, long long v) {
    if(L == st && ed == R) return Tag(p, v);
    Push(p); int mid = L + R >> 1;
    if(st <= mid) Upd(p << 1, L, mid, st, std::min(ed, mid), v);
    if(ed > mid) Upd(p << 1 | 1, mid + 1, R, std::max(mid + 1, st), ed, v);
    Upd(p);
}
void Que(int p, int L, int R) {
    if(L == R) return void(ans[L] = t[p]);
    Push(p); int mid = L + R >> 1;
    Que(p << 1, L, mid); Que(p << 1 | 1, mid + 1, R);
}
bool In(int u, int v) {return id[u] && id[v] && abs(id[u] - id[v]) == 1;}
int main() {
    memset(t, 0x3f, sizeof(t)); inf = t[0];
    n = read(); int m = read();
    for(int i = 1;i <= m; ++i) {
        U[i] = read(); V[i] = read(); W[i] = read();
        adds(U[i], V[i], W[i]);
    }
    int S = read(), T = read();
    Dij(S, f); Dij(T, g); tp = 0; long long D = g[S]; 
    if(D == inf) {
        int Q = read();
        for(int i = 1;i <= Q; ++i) puts("Infinity");
        return 0;
    }
    for(int i = S; i; i = Pr[i]) a[id[i] = ++tp] = i;
    for(int i = 1;i <= tp; ++i) Find(a[i], f, fs);
    for(int i = tp; i; --i) Find(a[i], g, ft);
    for(int i = 1;i <= m; ++i) {
        int u = U[i], v = V[i], w = W[i];
        if(!fs[u] || !fs[v] || In(u, v)) continue;
        if(id[fs[u]] < id[ft[v]]) Upd(1, 1, n, id[fs[u]], id[ft[v]] - 1, f[u] + g[v] + w);
        if(id[fs[v]] < id[ft[u]]) Upd(1, 1, n, id[fs[v]], id[ft[u]] - 1, f[v] + g[u] + w);
    }
    Que(1, 1, n); int Q = read();
    for(int i = 1;i <= Q; ++i) {
        int u = read(), v = read();
        if(!In(u, v)) printf("%lld\n", D);
        else {
            if(id[u] > id[v]) std::swap(u, v);
            if(ans[id[u]] == inf) puts("Infinity");
            else printf("%lld\n", ans[id[u]]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/80245529