ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P1967 [NOIP2013 提高组] 货车运输 题解

2022-08-19 00:01:52  阅读:119  来源: 互联网

标签:10 le idx sz int 题解 货车运输 son P1967


题目描述

A 国有 \(n\) 座城市,编号从 \(1\) 到 \(n\),城市之间有 \(m\) 条双向道路。每一条道路对车辆都有重量限制,简称限重。

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

输入格式

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

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

接下来一行有一个整数 \(q\),表示有 \(q\) 辆货车需要运货。

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

输出格式

共有 \(q\) 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。
如果货车不能到达目的地,输出 \(-1\)。

样例输入

4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3

样例输出

3
-1
3

对于 \(100\%\) 的数据,\(1 \le n < 10^4\),\(1 \le m < 5\times 10^4\),$1 \le q< 3\times 10^4 $,\(0 \le z \le 10^5\)。


Kruskal 重构树板子题,但我不想动脑子,所以使用 Kruskal 求最大生成树 + 树链剖分维护边权 + 线段树维护静态最小值。跑最大生成树的原因显然,贪心思想跟路径远近无关的情况下应该尽量沿着边权大的走,但限制两个点之间的距离承重又是两条路之间最小的那个决定的,原因它在一棵生成树上,两点之间有且只有一条路。

说点细节,树剖维护边权是要在第一遍 dfs 时将边权换为子节点点权,然后在第二遍 dfs 针对点权建立正反映射。

还有,查询时最后是从 \([id[v]+1,id[u]]\) 加一,加一,加一,剩下地方不变,不变,不变。

原题构造出来的可能是一颗森林所以需要以所有并查集的父节点都跑一遍树剖。

Code.

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=5e4+10,imax=INT_MAX;
int n,m,h[N],ne[N<<1],e[N<<1],w[N<<1],idx,p[N],dep[N],sz[N],fa[N],son[N],id[N],cnt,yl[N],top[N],val[N],q;
struct node
{
	int u,v,w;
	bool operator < (const node &o) const{
		return w > o.w;
	}
} pl[M];
void add(int u,int v,int c) {ne[++idx]=h[u],e[idx]=v,w[idx]=c,h[u]=idx;}
int find(int x) {if(p[x] != x) p[x]=find(p[x]); return p[x];}
void dfs1(int u,int father,int depth)
{
	dep[u]=depth; sz[u]=1; fa[u]=father;
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i]; if(j == father) continue ;
		val[j]=w[i]; dfs1(j,u,depth+1); sz[u]+=sz[j];
		if(sz[son[u]] < sz[j]) son[u]=j;
	}
}
void dfs2(int u,int t)
{
	id[u]=++cnt; yl[cnt]=val[u]; top[u]=t;
	if(! son[u]) return ; dfs2(son[u],t);
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i]; if(j == son[u] || j == fa[u]) continue ;
		dfs2(j,j);
	}
}
struct Seg
{
	struct node {int l,r,mn;} tr[N<<2];
	void pushup(int u) {tr[u].mn=min(tr[u<<1].mn,tr[u<<1|1].mn);}
	void build(int u,int l,int r)
	{
		tr[u].l=l,tr[u].r=r,tr[u].mn=imax;
		if(l == r) return tr[u].mn=yl[l],void();
		int mid = l + r >> 1;
		build(u<<1,l,mid); build(u<<1|1,mid+1,r);
		pushup(u);
	}
	int query(int u,int l,int r)
	{
		if(l <= tr[u].l && tr[u].r <= r) return tr[u].mn;
		int mid = tr[u].l + tr[u].r >> 1,res=imax;
		if(l<=mid) res=min(res,query(u<<1,l,r)); if(r>mid) res=min(res,query(u<<1|1,l,r));
		return res;
	}
} st;
int query(int u,int v)
{
	int res=imax;
	while(top[u] != top[v])
	{
		if(dep[top[u]] < dep[top[v]]) swap(u,v);
		res=min(res,st.query(1,id[top[u]],id[u]));
		u=fa[top[u]];
	}
	if(dep[u] < dep[v]) swap(u,v);
	res=min(res,st.query(1,id[v]+1,id[u]));
	return res;
}
int main()
{
	memset(h,-1,sizeof h); scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) p[i]=i;
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&pl[i].u,&pl[i].v,&pl[i].w);
	stable_sort(pl+1,pl+1+m);
	for(int i=1;i<=m;i++)
	{
		int u=find(pl[i].u),v=find(pl[i].v);
		if(u == v) continue ; p[u]=v;
		add(pl[i].u,pl[i].v,pl[i].w);
		add(pl[i].v,pl[i].u,pl[i].w);
	}
	for(int i=1;i<=n;i++)
	{
		if(p[i] != i) continue ; val[i]=imax;
		dfs1(i,0,1); dfs2(i,i);
	}
	st.build(1,1,n);
	scanf("%d",&q);
	while(q -- )
	{
		int u,v; scanf("%d%d",&u,&v);
		if(p[find(u)] != p[find(v)]) puts("-1");
		else printf("%d\n",query(u,v));
	}
	return 0;
}

标签:10,le,idx,sz,int,题解,货车运输,son,P1967
来源: https://www.cnblogs.com/EastPorridge/p/16600581.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有