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
,
g
考虑我们如果维护出来了这个信息之后该怎么做。
首先搞定最间单的情况,就是对最短路没有影响的情况。
我们随便找到一条最短路,如果删掉的边不在这条路径上那么肯定不会影响。
这个时候我们就要考虑删掉的边在路径上的情况。
这里要用一个巧妙的思路,就是换一个方向考虑,我们注意这条最短路之外的边对于这条最短路删去某条边的影响。
对于某条边可以贡献的最短路就是
fu+w(u,v)+gv
f
u
+
w
(
u
,
v
)
+
g
v
(无向边变成有向边)。
这个时候我们考虑这个
fu+w(u,v)+gv
f
u
+
w
(
u
,
v
)
+
g
v
可以应用到哪种情况上。
假设某两个点间的路径集合是
W(u,v)
W
(
u
,
v
)
我们假设
W(S,u)⋂W(S,T)=W(S,Su),W(v,T)⋂W(S,T)=W(Tv,T)
W
(
S
,
u
)
⋂
W
(
S
,
T
)
=
W
(
S
,
S
u
)
,
W
(
v
,
T
)
⋂
W
(
S
,
T
)
=
W
(
T
v
,
T
)
那么不难发现,如果是
W(Su,Tv)
W
(
S
u
,
T
v
)
中的任意一条边被删去之后,都可以用
fu+w(u,v)+gv
f
u
+
w
(
u
,
v
)
+
g
v
代替。
我们将
W(S,T)
W
(
S
,
T
)
上的边编号,用一个
DAGDP
D
A
G
D
P
搞出
Su,Tv
S
u
,
T
v
最后每条边线段树取个
min
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;
}