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