Histcat's Blog
一个高中生的小窝
P1967 [NOIP2013 提高组] 货车运输

题目

货车运输

A 国有 nn 座城市,编号从 11nn,城市之间有 mm 条双向道路。每一条道路对车辆都有重量限制,简称限重。

现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入格式

第一行有两个用一个空格隔开的整数 n,m n,m,表示 A 国有 n n 座城市和 mm 条道路。

接下来 mm 行每行三个整数 x,y,zx, y, z,每两个整数之间用一个空格隔开,表示从 xx 号城市到 yy 号城市有一条限重为 zz 的道路。 注意: xyx \neq y,两座城市之间可能有多条道路 。

接下来一行有一个整数 qq,表示有 qq 辆货车需要运货。

接下来 qq 行,每行两个整数 x,yx,y,之间用一个空格隔开,表示一辆货车需要从 xx 城市运输货物到 yy 城市,保证 xyx \neq y

对于 100%100\% 的数据,1n<1041 \le n < 10^41m<5×1041 \le m < 5\times 10^41q<3×1041 \le q< 3\times 10^4 0z1050 \le z \le 10^5

题解

由于要求路径上的最小值最大,所以 二分(当然可以,但我不会QAQ) 求出最大生成树来,然后对于每次询问的两点lca查询路径上的最小值即可

具体实现和lca差不多

问题

1.建双向边

2.并查集fa[/*!!!*/x_fa] = y;

3.125行取min写成了anc

代码

	#include<bits/stdc++.h>
	using namespace std;

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

	const int N = 1e4 + 10, M = 1e5 + 100;

	struct U
	{
		int x, y, z;
		bool operator < (const U o) const
		{
			return z > o.z;
		}
	}u[M >> 1]; int cnt = 1;

	int fa[N], n, m;

	int anc[N][20], path_min[N][20], depth[N];

	int getfa(int u)
	{
		if(fa[u] == u) return u;
		return fa[u] = getfa(fa[u]);
	}

	void merge(int x, int y)
	{
		int x_fa = getfa(x), y_fa = getfa(y);
		fa[/*!!!*/x_fa] = y;
	}

	int head[N], nxt[M], to[M], edge[M], tot = 1;

	void add(int x, int y, int z)
	{
		to[++tot] = y;
		edge[tot] = z;
		nxt[tot] = head[x];
		head[x] = tot;
	}

	void dfs(int u, int fa)
	{
		depth[u] = depth[fa] + 1;
		anc[u][0] = fa;
		for(int i = head[u]; i; i = nxt[i])
		{
			int v = to[i];
			if(v == fa) continue;
			path_min[v][0] = edge[i];
			dfs(v, u);
		}
	}

	void lca_init()
	{
		for(int j = 1;j < 20;j++)
		{
			for(int i = 1;i <= n;i++)
			{
				anc[i][j] = anc[anc[i][j - 1]][j - 1];
				path_min[i][j] = min(path_min[i][j - 1], path_min[anc[i][j - 1]][j - 1]);
			}
		}
	}

	int lca_query_anc(int x, int y)
	{
		if(depth[x] < depth[y])
			swap(x, y);
		for(int i = 19;i >= 0;i--)
		{
			if(depth[anc[x][i]] >= depth[y])
				x = anc[x][i];
		}
	
		if(x == y) return x;
	
		for(int i = 19;i >= 0;i--)
		{
			if(anc[x][i] != anc[y][i])
				x = anc[x][i], y = anc[y][i];
		}
		return anc[x][0];
	}

	int lca_query_min(int x, int y)
	{
		int ans = 0x3f3f3f3f;
		if(depth[x] < depth[y])
			swap(x, y);
		for(int i = 19;i >= 0;i--)
		{
			if(depth[anc[x][i]] >= depth[y])
			{
				ans = min(ans, path_min[x][i]);	x = anc[x][i]; 
			}
		}
		if(x == y) return ans;
		for(int i = 19;i >= 0;i--)
		{
			if(anc[x][i] != anc[y][i])
			{
				ans = min(ans, path_min[x][i]), ans = min(ans, path_min[y][i]);
				x = anc[x][i], y = anc[y][i];
			}
		}
		return min(ans, min(path_min[x][0], path_min[y][0]));
	}

	int main()
	{
		n = read(), m = read();
		for(int i = 1;i <= n;i++)
		{
			fa[i] = i;
		}
	
		int x, y, z;
		for(int i = 1;i <= m;i++)
		{
			x = read(), y = read(), z = read();
			u[cnt].x = x;
			u[cnt].y = y, u[cnt].z = z;
			++cnt;
		}
	
		sort(u + 1, u + 1 + m);
	
		for(int i = 1;i <= m;i++)
		{
			int x_fa = getfa(u[i].x), y_fa = getfa(u[i].y);
			if(x_fa != y_fa)
			{
				merge(u[i].x, u[i].y);
				add(u[i].x, u[i].y, u[i].z);
				add(u[i].y, u[i].x, u[i].z);
			}
		}
	
		for(int i = 1;i <= n;i++)
		{
			if(fa[i] == i)
			{
				dfs(i, 0);
			}
		}
		lca_init();
		int q;
		q = read();
	
//		for(int i = 1;i <= n;i++)
//		{
//			cout << "qwq "<<path_min[i][2] << endl;
//		}
	
		while(q--)
		{
			x = read(), y = read();
			int x_fa = getfa(x), y_fa = getfa(y);
			if(x_fa != y_fa)
			{
				printf("-1\n");
				continue;
			}
			cout << lca_query_min(x, y) << endl; 
	}

}