[CF1051F]The Shortest Statement

题目大意:给出一张$n$个点$m(m-nleqslant20)$条边的无向图,$q$询问两点之间的最短路。$n,m,q⩽10^5$

题解:询问$10^5$肯定不能每次求最短路,发现$m-nleqslant20$,也就是说这张图是一棵树加上最多$21$一条非树边,这$21$条非树边最多连接$42$个不同的点。答案要么是在树上的答案($dep_u+dep_v-2dep_{LCA(u,v)}$),要么就经过了至少一条非树边。

至少经过一条非树边比较难处理。可以对每个连接了非树边的点跑一遍最短路,因为这是唯一导致答案变小的方案。

卡点:求$LCA$时$x,y$写反,导致减乘负数($Codeforces$评测机好评,每次$RE$都可以帮我找到哪出锅了)

C++ Code:

#include <cstdio>
#include <cstring>
#include <queue>
#define maxn 100010
#define maxm 100030
#define maxk 45
const long long inf = 0x3f3f3f3f3f3f3f3f;
inline long long min(long long a, long long b) {return a < b ? a : b;}

int head[maxn], cnt = 1;
struct Edge {
	int to, nxt;
	long long w;
	bool tree;
} e[maxm << 1];
inline void addE(int a, int b, long long c) {
	e[++cnt] = (Edge) {b, head[a], c, false}; head[a] = cnt;
}
int n, m;
namespace Tree {
	#define M 18
	int fa[maxn][M + 1], dep[maxn];
	long long sum[maxn];
	void dfs(int u) {
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			if (dep[v]) continue;
			fa[v][0] = u; dep[v] = dep[u] + 1;
			sum[v] = sum[u] + e[i].w;
			e[i].tree = e[i ^ 1].tree = true;
			dfs(v);
		}
	}
	inline void init(int rt) {
		dep[rt] = 1;
		dfs(rt);
		for (int i = 1; i <= M; i++) 
			for (int j = 1; j <= n; j++) 
				fa[j][i] = fa[fa[j][i - 1]][i - 1];
	}
	inline int LCA(int x, int y) {
		if (x == y) return x;
		if (dep[x] < dep[y]) std::swap(x, y);
		for (int i = dep[x] - dep[y]; i; i &= i - 1) x = fa[x][__builtin_ctz(i)];
		if (x == y) return x;
		for (int i = M; ~i; i--) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
		return fa[x][0];
	}
	#undef M
}
using Tree::LCA;
using Tree::sum;

int S[maxk], top;
bool vis[maxn];
long long d[maxk][maxn];
struct node {
	int p;
	long long d;
	node () {p = d = 0;}
	node (int __p, long long __d = 0) {p = __p, d = __d;}
	inline bool operator < (const node &rhs) const {return d > rhs.d;}
};
std::priority_queue<node> q;
void dij(int S, long long *d) {
	while (!q.empty()) q.pop();
	for (int i = 1; i <= n; i++) d[i] = inf, vis[i] = false;
	d[S] = 0;
	q.push(node(S));
	while (!q.empty()) {
		int u = q.top().p; q.pop();
		if (vis[u]) continue;
		vis[u] = true;
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			if (d[v] > d[u] + e[i].w) {
				d[v] = d[u] + e[i].w;
				q.push(node(v, d[v]));
			}
		}
	}
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 0, a, b, c; i < m; i++) {
		scanf("%d%d%d", &a, &b, &c);
		addE(a, b, c);
		addE(b, a, c);
	}
	Tree::init(1);
	for (int i = 2; i <= cnt; i += 2) {
		if (!e[i].tree) {
			int u = e[i ^ 1].to, v = e[i].to;
			if (!vis[u]) S[++top] = u, vis[u] = true;
			if (!vis[v]) S[++top] = v, vis[v] = true;
		}
	}
	for (int i = 1; i <= top; i++) dij(S[i], d[i]);
	int QQ;
	scanf("%d", &QQ);
	while (QQ --> 0) {
		int u, v;
		scanf("%d%d", &u, &v);
		long long ans = sum[u] + sum[v] - sum[LCA(u, v)] * 2;
		for (int i = 1; i <= top; i++) {
			ans = min(ans, d[i][u] + d[i][v]);
		}
		printf("%lld
", ans);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/Memory-of-winter/p/9744320.html