题解【洛谷P1967】[NOIP2013]货车运输

题面

题解

注意到有一些限重很低的边不会被走到。

于是考虑建一棵最大生成树,在生成树上寻找答案。

\(f[i][j]\)表示\(i\)\(2^j\)级祖先,\(w[i][j]\)表示\(i\)\(2^j\)级祖先的最大载重。

那么我们在倍增寻找\(\text{LCA}\)时更新答案即可。

代码

#include <bits/stdc++.h>
#define itn int
#define gI gi

using namespace std;

inline int gi()
{
	int f = 1, x = 0; char c = getchar();
	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') x = x * 10 + (c ^ 48), c = getchar();
	return f * x;
}

const int maxn = 100003;

int q, n, m, tot, head[maxn], ver[maxn], edge[maxn], nxt[maxn], fa[maxn][23];
int f[maxn], w[maxn][23], vis[maxn], dep[maxn];
struct Node
{
	int u, v, w;
} e[maxn];

inline bool cmp(Node x, Node y) {return x.w > y.w;}

int getf(int u)
{
	if (f[u] == u) return u;
	return f[u] = getf(f[u]);
}

inline void add(int u, int v, int w)
{
	ver[++tot] = v, nxt[tot] = head[u], edge[tot] = w, head[u] = tot;
}

inline void get_MST()
{
	for (int i = 1; i <= n; i+=1) f[i] = i;
	for (int i = 1; i <= m; i+=1)
	{
		int U = getf(e[i].u), V = getf(e[i].v);
		if (U != V)
		{
			f[U] = V;
			add(e[i].u, e[i].v, e[i].w);
			add(e[i].v, e[i].u, e[i].w);
		}
	}
}

void dfs(int u)
{
	vis[u] = 1;
	for (int i = head[u]; i; i = nxt[i])
	{
		int v = ver[i], ww = edge[i];
		if (vis[v]) continue;
		dep[v] = dep[u] + 1;
		fa[v][0] = u;
		w[v][0] = ww;
		dfs(v);
	}
}

inline int getans(int u, int v)
{
	if (dep[u] > dep[v]) swap(u, v);
	int uu = 0x3f3f3f3f;
	for (int i = 20; i >= 0; i-=1)
	{
		if (dep[fa[v][i]] >= dep[u]) uu = min(uu, w[v][i]),  v = fa[v][i];
	}
	if (u == v) return uu;
	for (int i = 20; i >= 0; i-=1)
	{
		if (fa[u][i] != fa[v][i])
		{
			uu = min(uu, min(w[u][i], w[v][i]));
			u = fa[u][i], v = fa[v][i];
		}
	}
	uu = min(uu, min(w[u][0], w[v][0]));
	return uu;
}

int main()
{
	//freopen(".in", "r", stdin);
	//freopen(".out", "w", stdout);
	n = gi(), m = gi();
	for (int i = 1; i <= m; i+=1)
	{
		int u = gi(), v = gi(), w = gi();
		e[i].u = u, e[i].v = v, e[i].w = w;
	}
	sort(e + 1, e + 1 + m, cmp);
	get_MST();
	for (int i = 1; i <= n; i+=1)
	{
		if (!vis[i])
		{
			dep[i] = 1;
			dfs(i);
			fa[i][0] = i;
			w[i][0] = 0x3f3f3f3f;
		}
	}
	for (int i = 1; i <= 20; i+=1)
		for (int j = 1; j <= n; j+=1)
			fa[j][i] = fa[fa[j][i - 1]][i - 1],
				w[j][i] = min(w[j][i - 1], w[fa[j][i - 1]][i - 1]);
	q = gi();
	while (q--)
	{
		int u = gi(), v = gi();
		if (getf(u) != getf(v)) {puts("-1"); continue;}
		printf("%d\n", getans(u, v));
	}
	return 0;
}
posted @ 2019-11-10 16:03  csxsi  阅读(130)  评论(0编辑  收藏  举报