CodeForces - 843D Dynamic Shortest Path

Description

一个 \(n\) 个点 \(m\) 条边的带权有向图, \(q\) 次询问,询问有两种:

  • \(1 \ v\) :求 \(1\)\(v\) 的最短路。
  • \(2 \ c \ l_1 \ l_2 \cdots l_c\) :把编号为 \(l_1,l_2,\cdots ,l_c\) 的边的边权增加一。

\(n,m\le 10^5,q\le 2000,w\le 10^9\)

Solution

大力每次跑 dijkstra 的复杂度是 \(O[q(n+m)\log_2n]\) 的,完蛋。

考虑跑完 dijkstra 之后对于某条边 \((u,v,w)\) ,有 \(dis[v] \le dis[u]+w\)

那么在原图上跑一遍 dijkstra 后就把边 \((u,v,w)\) 给改成 \((u,v, dis[u]+w-dis[v])\) 。这样改了以后跑最短路,意义就变成了与原图最短路的差。差是一定不会大于 \(min(c,n-1)\) 的。于是就可以不用优先队列,用 \(n\) 个普通的队列,这样就可以去掉之前复杂度里的 \(\log_2 n\) ,变成 \(O[q(n+m)]\) ,就可以过(?)了。

#include<bits/stdc++.h>
using namespace std;

template <class T> void read(T &x) {
	x = 0; bool flag = 0; char ch = getchar(); for (; ch < '0' || ch > '9'; ch = getchar()) flag |= ch == '-';
	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48; flag ? x = ~x + 1 : 0;
}

#define N 100010
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define ll long long 
#define INF 0x3f3f3f3f3f3f3f3f

struct edge { int v, w, next; }e[N];
int head[N];
inline void add(int u, int v, int w) {
	static int tot; e[++tot].v = v, e[tot].w = w, e[tot].next = head[u], head[u] = tot;
}

ll dis[N];
int dis2[N];

#define pli pair<ll, int>
priority_queue<pli, vector<pli >, greater<pli > > q;
queue<int> q2[N];
bool vis[N];

int main() {
	int n, m, Q; read(n), read(m), read(Q);
	rep(i, 1, m) {
		int u, v, w; read(u), read(v), read(w);
		add(u, v, w);
	}
	q.push(pli(0, 1));
	memset(dis, 0x3f, sizeof dis); dis[1] = 0;
	while (!q.empty()) {
		int u = q.top().second; q.pop();
		if (vis[u]) continue; vis[u] = 1;
		for (int i = head[u], v; i; i = e[i].next) if (dis[v = e[i].v] > dis[u] + e[i].w)
			dis[v] = dis[u] + e[i].w, q.push(pli(dis[v], v));
	}
	while (Q--) {
		int op, k, x; read(op), read(k);
		if (op == 1) printf("%lld\n", dis[k] < INF ? dis[k] : -1);
		else {
			rep(i, 1, k) read(x), e[x].w++;
			memset(dis2, 0x3f, sizeof dis2);
			q2[0].push(1); dis2[1] = 0;
			int mx = 0;
			rep(i, 0, mx) while (!q2[i].empty()) {
				int u = q2[i].front(); q2[i].pop();
				if (dis2[u] < i) continue;
				for (int j = head[u], v, t; j; j = e[j].next)
					if (dis2[v = e[j].v] > (t = dis2[u] + (e[j].w + dis[u] - dis[v]))) {
						dis2[v] = t;
						if (t <= min(n - 1, k)) q2[t].push(v), mx = max(mx, t);
					}	
			}
			rep(i, 1, n) dis[i] = min(INF, dis[i] + dis2[i]);
		}
	}
	return 0;
}

posted @ 2018-09-05 10:12  aziint  阅读(349)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.