题意:一个无向图,保证点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; }