[luogu1967] 货车运输

题面

​ 这个题目第一眼看觉得是道最短路,但是一看数据范围,有3e5次询问,1e5个点,所以最终用上dijkstra的时间复杂度便是:

\[O(qn ^ 2) \]

加上堆优化之后也只有:

\[O(qn\log_{2}^{n}) \]

所以,我们肯定只能用别的方法来做了。

​ 继续看题,题目中如是说道:"司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。", 又这样说道:"x 不等于 y,两座城市之间可能有多条道路 。" 这句话是很重要的,它说明了若是x, y之间有多余的边,那么只取其中最长的那条边就是了, 所以这就是最大生成树了, 因为两两之间只有一条边。

等会, 好像还是有点问题

​ 若两个点之间不联通呢??? 那我们就不建树, 建一棵最大生成森林就可以了, 如果询问的两个点不在同一棵树中的话,就输出不成立。至于查询两点间的距离的话, 不是LCA的模版题吗, 这道题就被我们完美(莫名其妙)地解决了。所以,一个题只要剖析清楚,其实就没有那么难了。

代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define N 100005
#define M 500005
using namespace std;

int n, m, head[N], cnt, fa[N], tot, rnk[N], f[N][25], dis[N][25], dep[N], q;
struct node
{
	int to, from, cost, next; 
} edge[M << 1], e[N << 1]; 

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

inline void add(int u, int v, int w) { edge[++cnt].to = v; edge[cnt].from = u; edge[cnt].next = head[u]; edge[cnt].cost = w; head[u] = cnt; }

inline void adde(int u, int v, int w) { e[++tot].to = v; e[tot].from = u; e[tot].cost = w; e[tot].next = head[u]; head[u] = tot; }

inline bool cmp(node a, node b) { return a.cost > b.cost; }

inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }

inline void merge(int x, int y)
{
	x = find(x); y = find(y);
	if(rnk[x] < rnk[y]) fa[x] = y; 
	else if(rnk[x] > rnk[y]) fa[y] = x;
	else { fa[x] = y; rnk[y]++; }
}

inline void Kruskal()
{
	memset(head, 0, sizeof(head)); 
	for(int i = 1; i <= n; i++) { fa[i] = i; rnk[i] = 1; }
	sort(edge + 1, edge + cnt + 1, cmp); 
	for(int i = 1; i <= cnt; i++)
	{
		int u = edge[i].from, v = edge[i].to; 
		int r1 = find(u), r2 = find(v);
		if(r1 != r2)
		{
			merge(r1, r2);
			adde(u, v, edge[i].cost); adde(v, u, edge[i].cost); 
		}
	}
}

inline void dfs(int u, int fa)
{
	f[u][0] = fa; dep[u] = dep[fa] + 1; 
	for(int i = 1; i <= 20 && f[f[u][i - 1]][i - 1]; i++)
	{
		f[u][i] = f[f[u][i - 1]][i - 1];
		dis[u][i] = min(dis[u][i - 1], dis[f[u][i - 1]][i - 1]); 
	}
	for(int i = head[u]; i; i = e[i].next)
	{
		int v = e[i].to; if(v == fa) continue;
		dis[v][0] = e[i].cost; dfs(v, u); 
	}
}

inline int lca(int u, int v)
{
	if(dep[u] > dep[v]) swap(u, v);
	int ans = 1e9;
	for(int i = 18; i >= 0; i--)
		if(dep[f[v][i]] >= dep[u])
		{
			ans = min(ans, dis[v][i]); 
			v = f[v][i]; 
		}
	if(u == v) return ans;
	for(int i = 20; i >= 0; i--)
		if(f[u][i] != f[v][i])
		{
			ans = min(ans, min(dis[v][i], dis[u][i]));
			v = f[v][i]; u = f[u][i]; 
		}
	ans = min(ans, min(dis[v][0], dis[u][0]));
	return ans; 
}

int main()
{
	memset(f, 0, sizeof(f)); 
	n = read(); m = read();
	for(int i = 1; i <= m; i++)
	{
		int u = read(), v = read(), w = read();
		add(u, v, w); 
	}
	Kruskal(); 
	for(int i = 1; i <= n; i++)
		if(!dep[i])
			dfs(i, 0); 
	q = read(); 
	for(int i = 1; i <= q; i++)
	{
		int x = read(), y = read(); 
		if(find(x) != find(y)) { puts("-1"); continue; }
		printf("%d\n", lca(x, y)); 
	}
	return 0;
}

posted @ 2019-02-19 21:47  ztlztl  阅读(176)  评论(0编辑  收藏  举报