K 短路

这种东西到现在才学……

考虑 \(T\) 为根的最短路树,一条路径一定是树上边和非树边交错。

我们只管非树边,对于一条路径,非树边构成一个序列 \(L\),相邻两条路径 \(\left(u_1,v_1\right)\)\(\left(u_2,v_2\right)\) 显然一定满足 \(u_2\)\(v_1\) 的祖先。

有了这个性质,我们可以解决这个问题。

考虑最后一条边的转移。要么是转移到答案,即 \(dis_u + val + dis_v\),要么再选择一条边转移,即 \(dis_u' = dis_u + val + dis_{u,v}\),其中 \(v\) 是下一条边的 \(u\) 的最近祖先端点。

显然可以用堆维护。由于答案是两个转移式结合,显然还是太繁了。不如直接把所有边权改为 \(val' = val + dis_v - dis_u\),那么显然经过一条边只是最短路的增量。

每次一条边的转移直接把距离加上 \(val'\) 即可。

调试的时候把最短路数组和左偏树数组混用了 /px

#include <bits/stdc++.h>

const int MAXN = 5010;
const int MAXE = 200010;
const int MAXP = 2000000;
const double eps = 1e-6;
int n, m;
int xs[MAXE], ys[MAXE];
double vs[MAXE], E, dis[MAXN];
std::vector<int> G[MAXN], el[MAXN];
inline bool eq(double x) { return -eps < x && x < eps; }
struct node {
	int to, ls, rs; double val;
} tree[MAXP];
int tot;
int dx[MAXP];
int merge(int x, int y) {
	if (!x || !y) return x | y;
	if (tree[x].val > tree[y].val) std::swap(x, y);
	int now = ++tot; node & t= tree[now] = tree[x];
	t.rs = merge(t.rs, y);
	if (dx[t.ls] < dx[t.rs]) std::swap(t.ls, t.rs);
	dx[now] = dx[t.rs] + 1;
	return now;
}
void shortestpath() {
	for (int i = 1; i <= m; ++i)
		G[ys[i]].push_back(i);
	for (int i = 0; i < n; ++i)
		dis[i] = 1e20;
	dis[n] = 0;
	static bool vis[MAXN];
	for (int i = 1; i <= n; ++i) {
		int at = 0;
		for (int j = 1; j <= n; ++j)
			if (!vis[j] && dis[j] < dis[at])
				at = j;
		vis[at] = true;
		const int SZ = G[at].size();
		for (int j = 0; j != SZ; ++j) {
			int u = G[at][j];
			dis[xs[u]] = std::min(dis[xs[u]], dis[at] + vs[u]);
		}
	}
	memset(vis, 0, n + 1);
	for (int i = 1; i <= n; ++i) G[i].clear();
	for (int i = 1; i <= m; ++i)
		if (eq(-dis[xs[i]] + dis[ys[i]] + vs[i]))
			if (!vis[xs[i]]) {
				vis[xs[i]] = true;
				G[ys[i]].push_back(xs[i]);
			}
	for (int i = 1; i <= m; ++i)
		el[xs[i]].push_back(i);
}
int rt[MAXN];
void dfs(int u, int fa = 0) {
	rt[u] = rt[fa];
	const int LZ = el[u].size();
	bool fir = false;
	for (int i = 0; i != LZ; ++i) {
		int at = el[u][i];
		double v = dis[ys[at]] + vs[at] - dis[u];
		if (v < eps && !fir) { fir = true; continue; }
		++tot;
		tree[tot].to = ys[at];
		tree[tot].val = v;
		rt[u] = merge(rt[u], tot);
	}
	const int SZ = G[u].size();
	for (int i = 0; i != SZ; ++i)
		dfs(G[u][i], u);
}
struct qs {
	int rt; double v;
	bool operator < (const qs & b) const {
		return v > b.v;
	}
} ;
std::priority_queue<qs> q;
qs trans(int rt, double v) {
	qs res;
	res.rt = rt, res.v = v + tree[rt].val;
	return res;
}
int main() {
	std::ios_base::sync_with_stdio(false), std::cin.tie(0);
	std::cin >> n >> m >> E;
	for (int i = 1; i <= m; ++i)
		std::cin >> xs[i] >> ys[i] >> vs[i];
	shortestpath();
	dfs(n);
	++tot; tree[tot].to = 1;
	tree[tot].val = dis[1];
	q.push(trans(tot, 0));
	int ans = 0;
	while (true) {
		qs x = q.top(); q.pop();
		E -= x.v;
		if (E + eps <= 0) break;
		++ans;
		if (int t = rt[tree[x.rt].to])
			q.push(trans(t, x.v));
		x.v -= tree[x.rt].val;
		x.rt = merge(tree[x.rt].ls, tree[x.rt].rs);
		if (x.rt) q.push(trans(x.rt, x.v));
	}
	std::cout << ans << std::endl;
	return 0;
}
posted @ 2019-10-15 21:52  daklqw  阅读(203)  评论(0编辑  收藏  举报