【BZOJ2125】最短路

【题目链接】

【思路要点】

  • 建立圆方树,预处理根节点到每个圆点的最短路的长度\(dist_i\)。
  • 询问时分Lca为圆点和方点分别讨论。
  • Lca为圆点,那么答案就是\(dist_x+dist_y-2*dist_{Lca}\)。
  • Lca为方点,那么答案就是\(dist_x-dist_{tx}+dist_y-dist_{ty}+query(Lca,tx,ty)\)。
  • 其中\(tx\)、\(ty\)分别为由\(Lca\)向\(x\)和\(y\)走一步所到达的节点,\(query(Lca,tx,ty)\)为\(tx\)与\(ty\)之间在环上的最短路。
  • 时间复杂度\(O(NLogN+QLogN)\)。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 20005;
const int MAXLOG = 15;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct edge {int dest, len; };
vector <edge> a[MAXN];
vector <int> b[MAXN];
map <int, int> mp[MAXN], c[MAXN];
int n, m, q, oldn;
int top, Stack[MAXN], len[MAXN];
int timer, dfn[MAXN], low[MAXN];
int father[MAXN][MAXLOG], depth[MAXN], dist[MAXN];
int query(int from, int x, int y) {
	int tmp = abs(c[from][x] - c[from][y]);
	return min(tmp, len[from] - tmp);
}
void work(int pos, int fa) {
	father[pos][0] = fa;
	depth[pos] = depth[fa] + 1;
	for (int i = 1; i < MAXLOG; i++)
		father[pos][i] = father[father[pos][i - 1]][i - 1];
	if (pos <= oldn) {
		int f = father[fa][0];
		if (pos == 1) dist[pos] = 0;
		else dist[pos] = dist[f] + query(fa, pos, f);
		for (unsigned i = 0; i < b[pos].size(); i++)
			if (b[pos][i] != fa) work(b[pos][i], pos);
	} else {
		for (unsigned i = 0; i < b[pos].size(); i++)
			if (b[pos][i] != fa) work(b[pos][i], pos);
	}
}
void tarjan(int pos) {
	Stack[++top] = pos;
	dfn[pos] = low[pos] = ++timer;
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (dfn[a[pos][i].dest] == 0) {
			tarjan(a[pos][i].dest);
			chkmin(low[pos], low[a[pos][i].dest]);
			if (low[a[pos][i].dest] >= dfn[pos]) {
				int tmp = 0, last = 0; n++;
				while (tmp != a[pos][i].dest) {
					last = tmp;
					tmp = Stack[top--];
					b[n].push_back(tmp);
					b[tmp].push_back(n);
					if (last == 0) len[n] += mp[tmp][pos];
					else len[n] += mp[tmp][last];
					c[n][tmp] = len[n];
				}
				b[n].push_back(pos);
				b[pos].push_back(n);
				len[n] += mp[pos][tmp];
				c[n][pos] = len[n];
			}
		} else chkmin(low[pos], dfn[a[pos][i].dest]);
}
int lca(int x, int y) {
	if (depth[x] < depth[y]) swap(x, y);
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (depth[father[x][i]] >= depth[y]) x = father[x][i];
	if (x == y) return x;
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (father[x][i] != father[y][i]) {
			x = father[x][i];
			y = father[y][i];
		}
	return father[x][0];
}
int getans(int x, int y, int z) {
	int ans = dist[x] + dist[y];
	for (int i = MAXLOG - 1; i >= 0; i--) {
		if (depth[father[x][i]] > depth[z]) x = father[x][i];
		if (depth[father[y][i]] > depth[z]) y = father[y][i];
	}
	ans -= dist[x] + dist[y];
	ans += query(z, x, y);
	return ans;
}
int main() {
	read(n), read(m), read(q), oldn = n;
	for (int i = 1; i <= m; i++) {
		int x, y, z;
		read(x), read(y), read(z);
		if (mp[x].count(y)) chkmin(mp[x][y], z);
		else mp[x][y] = z;
		if (mp[y].count(x)) chkmin(mp[y][x], z);
		else mp[y][x] = z;
		a[x].push_back((edge) {y, z});
		a[y].push_back((edge) {x, z});
	}
	tarjan(1);
	work(1, 0);
	for (int i = 1; i <= q; i++) {
		int x, y;
		read(x), read(y);
		int z = lca(x, y);
		if (z <= oldn) writeln(dist[x] + dist[y] - 2 * dist[z]);
		else writeln(getans(x, y, z));
	}
	return 0;
}

发布了794 篇原创文章 · 获赞 82 · 访问量 16万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览