CF843D Dynamic Shortest Path

首先,跑两千次 dijk 或者 spfa 肯定是不行的。

发现每次只会给边权加一,并且一共才加 $10^6$ 次,所以最短路长度的增加量其实只有 $10^6$ 级别。

我们考虑去求这个增加量。有一个操作:先设最开始跑一遍最短路后 $1$ 到 $u$ 的最短路为 $dis_u$ ,对于一条边 $u\to v$ 设其权值为 $w$ ,那么把它的权值改成 $w + dis_u - dis_v$ 。由于 $dis_u + w \ge dis_v$ 所以这个值肯定是非负的,且如果这条边在 $1$ 到 $v$ 的最短路上时它的权值一定是 $0$ 。在这样操作之后,不难发现 $1$ 到所有点的最短路长度都为 $0$ 了。

于是考虑在新图上加权值,然后在新图上跑最短路。可以发现,这样跑出来的最短路就是修改后对原图最短路的增加量。我们知道,增加量是不超过 $10^6$ 的,所以直接拿桶代替堆来跑 dijk 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "cmath"
#include "vector"
#include "map"
#include "set"
#include "queue"
#include "assert.h"

using namespace std;
#define MAXN 200006
//#define int long long
#define rep( i , a , b ) for (int i = (a), i##end = (b); i <= i##end; ++i)
#define per( i , a , b ) for (int i = (a), i##end = (b); i >= i##end; --i)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define all( x ) (x).begin() , (x).end()
#define mem( a ) memset( a , 0 , sizeof a )
typedef long long ll;
#define P 998244353
int n , m , q;
vector<pair<int,ll> > G[MAXN];

priority_queue<pair<ll,int> > Q;
ll dis[MAXN]; int vis[MAXN];

void dijk( ) {
Q.push( mp( 0 , 1 ) );
memset( dis , 0x3f3f , sizeof dis );
dis[1] = 0;
while( !Q.empty( ) ) {
int u = Q.top( ).se;
Q.pop( );
if( vis[u] ) continue;
vis[u] = 1;
for( auto &t : G[u] ) {
int v = t.fi;
if( dis[v] > dis[u] + t.se ) dis[v] = dis[u] + t.se , Q.push( mp( -dis[v] , v ) );
}
}
}

pii ed[MAXN];

ll d[MAXN];
vector<int> que[1000006];

void dij( ) {
que[0].pb( 1 );
memset( d , 0x3f3f , sizeof d );
mem( vis );
d[1] = 0;
for( int cur = 0 ; cur <= 1000000 ; ++cur ) {
while( !que[cur].empty( ) ) {
int u = que[cur].back( );
que[cur].pop_back( );
if( vis[u] ) continue;
vis[u] = 1;
for( auto &t : G[u] ) {
int v = t.fi;
if( d[v] > d[u] + t.se ) {
d[v] = d[u] + t.se;
if( d[v] <= 1000000 ) que[d[v]].pb( v );
}
}
}
}
}

void solve( ) {
cin >> n >> m >> q;
rep( i , 1 , m ) {
static int u , v , w;
scanf( "%d%d%d" , &u , &v , &w );
ed[i] = mp( u , G[u].size( ) );
G[u].eb( mp( v , w ) );
}
dijk( );
rep( i , 1 , n ) for( auto &t : G[i] ) t.se += dis[i] - dis[t.fi];
int opt , c , e;
rep( i , 1 , q ) {
scanf( "%d" , &opt );
if( opt == 1 ) {
dij( );
scanf( "%d" , &c );
printf( "%lld\n" , d[c] + dis[c] > 1e18 ? -1 : d[c] + dis[c] );
} else {
scanf( "%d" , &c );
rep( j , 1 , c ) {
scanf( "%d" , &e );
++G[ed[e].fi][ed[e].se].se;
}
}
}
}

signed main( ) {
// freopen("input","r",stdin);
// freopen("fuckout","w",stdout);
// int T;cin >> T;while( T-- ) solve();
solve( );
}
文章作者: yijan
文章链接: https://yijan.co/cf843d-dynamic-shortest-path/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog