大意: n结点有向有权图, m个操作, 增加若干边的权重或询问源点为1的单源最短路.
本题一个特殊点在于每次只增加边权, 并且边权增加值很小, 询问量也很小. 我们可以用johnson的思想, 转化为差值最短路, 这样边权就在n-1以内, 可以直接暴力跑桶优化dijkstra.
#include <iostream> #include <algorithm> #include <cstdio> #include <math.h> #include <set> #include <map> #include <queue> #include <string> #include <string.h> #include <bitset> #define REP(i,a,n) for(int i=a;i<=n;++i) #define PER(i,a,n) for(int i=n;i>=a;--i) #define hr putchar(10) #define pb push_back #define lc (o<<1) #define rc (lc|1) #define mid ((l+r)>>1) #define ls lc,l,mid #define rs rc,mid+1,r #define x first #define y second #define io std::ios::sync_with_stdio(false) #define endl ' ' using namespace std; typedef long long ll; typedef pair<ll,int> pli; const int N = 1e5+10; const ll INF = 0x3f3f3f3f3f3f3f3f; int n, m, q; struct _ {int to,w;} E[N]; vector<int> g[N]; int vis[N], d2[N]; ll d[N]; priority_queue<pli,vector<pli>, greater<pli> > Q; queue<int> q2[N]; void Dij() { memset(d,0x3f,sizeof d); Q.push(pli(d[1]=0,1)); while (Q.size()) { int u = Q.top().y; Q.pop(); if (vis[u]) continue; vis[u] = 1; for (auto &&id:g[u]) { auto &e = E[id]; ll dd = d[u]+e.w; if (dd<d[e.to]) Q.push(pli(d[e.to]=dd,e.to)); } } } void Dij2(int k) { REP(i,1,k) {int t; scanf("%d", &t), ++E[t].w;} memset(d2,0x3f,sizeof d2); q2[0].push(1), d2[1] = 0; int mx = 0; REP(i,0,mx) while (q2[i].size()) { int u = q2[i].front(); q2[i].pop(); if (d2[u]<i) continue; for (auto &&id:g[u]) { auto &e = E[id]; int dd = d2[u]+(e.w+d[u]-d[e.to]); if (dd<d2[e.to]) { d2[e.to] = dd; if (dd<=min(n-1,k)) { q2[dd].push(e.to); mx = max(mx, dd); } } } } REP(i,1,n) d[i]=min(INF,d[i]+d2[i]); } int main() { scanf("%d%d%d", &n, &m, &q); REP(i,1,m) { int u; scanf("%d%d%d", &u, &E[i].to, &E[i].w); g[u].pb(i); } Dij(); while (q--) { int op, x; scanf("%d%d", &op, &x); if (op==1) printf("%lld ", d[x]<INF?d[x]:-1); else Dij2(x); } }