P1967 货车运输【LCA】【生成树】
题目描述
A 国有 nn 座城市,编号从 11 到 nn,城市之间有 mm 条双向道路。每一条道路对车辆都有重量限制,简称限重。
现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入格式
第一行有两个用一个空格隔开的整数 n,mn,m,表示 AA 国有 nn 座城市和 mm 条道路。
接下来 mm 行每行三个整数 x, y, zx,y,z,每两个整数之间用一个空格隔开,表示从 xx 号城市到 yy 号城市有一条限重为 zz 的道路。
注意: x \neq yx=y,两座城市之间可能有多条道路 。
接下来一行有一个整数 qq,表示有 qq 辆货车需要运货。
接下来 qq 行,每行两个整数 x,yx,y,之间用一个空格隔开,表示一辆货车需要从 xx 城市运输货物到 yy 城市,保证 x \neq yx=y
输出格式
共有 qq 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。
如果货车不能到达目的地,输出 -1−1。
输入输出样例
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
3
-1
3
思路
这题Floyd肯定是不能做的,考虑其他办法。
类似于静态树上求节点之间的最小边权可做。
显然这颗静态树的边权要尽可能的大,且注意到很多较小的重边是不用去跑的,所以考虑只把最大的边加入连通块,舍弃小的重边。
对于两座城市,如果不在同一个连通块内,当然是不能跑的,输出-1;
如果在同一个连通块内,因为边点和询问的数量级过大,显然正常的枚举是不足以胜任此题要求的。
这就涉及到静态树上求节点之间的最小边权问题。
对于这种问题,可以上树链剖分用线段树来维护,也可以用树上问题的经典解法LCA来求解。
在处理 f 数组的过程中维护一个 dis 数组用以表示点间最小边权值即可。
CODE
#include <bits/stdc++.h>
#define dbg(x) cout << #x << "=" << x << endl
#define eps 1e-8
#define pi acos(-1.0) using namespace std;
typedef long long LL; template<class T>inline void read(T &res)
{
char c;T flag=;
while((c=getchar())<''||c>'')if(c=='-')flag=-;res=c-'';
while((c=getchar())>=''&&c<='')res=res*+c-'';res*=flag;
} namespace _buff {
const size_t BUFF = << ;
char ibuf[BUFF], *ib = ibuf, *ie = ibuf;
char getc() {
if (ib == ie) {
ib = ibuf;
ie = ibuf + fread(ibuf, , BUFF, stdin);
}
return ib == ie ? - : *ib++;
}
} int qread() {
using namespace _buff;
int ret = ;
bool pos = true;
char c = getc();
for (; (c < '' || c > '') && c != '-'; c = getc()) {
assert(~c);
}
if (c == '-') {
pos = false;
c = getc();
}
for (; c >= '' && c <= ''; c = getc()) {
ret = (ret << ) + (ret << ) + (c ^ );
}
return pos ? ret : -ret;
} const int maxn = 1e5 + ; int n, m, cnt;
int head[maxn << ], edge[maxn << ], nxt[maxn << ];
int fa[maxn], f[maxn][], depth[maxn], w[maxn << ];
int dis[maxn][]; bool vis[maxn]; struct node {
int u, v, w;
} e[maxn << ]; bool cmp(node a, node b) {
return a.w > b.w;
} void BuildGraph(int u, int v, int c) {
cnt++;
edge[cnt] = v;
nxt[cnt] = head[u];
w[cnt] = c;
head[u] = cnt;
} int fid(int x) {
return x == fa[x] ? x : fid(fa[x]);
} void join() {
sort(e+, e+m+, cmp);
for ( int i = ; i <= n; ++i ) {
fa[i] = i;
}
for ( int i = ; i <= m; ++i ) {
int eu = fid(e[i].u), ev = fid(e[i].v);
if(eu != ev) {
fa[eu] = ev;
BuildGraph(e[i].u, e[i].v, e[i].w);
BuildGraph(e[i].v, e[i].u, e[i].w);
//dbg(e[i].w);
}
}
} void dfs(int x) {//找x和y的最近公共祖先
vis[x] = ;
for ( int i = head[x]; i; i = nxt[i] ) {
int y = edge[i];
if(!vis[y]) {
depth[y] = depth[x] + ;
f[y][] = x;//y向上跳肯定是x
dis[y][] = w[i];
dfs(y);
}
}
} int lca(int x, int y) {//查找xy的最近公共祖先
int ans = 0x3f3f3f3f;
if(fid(x) != fid(y)) {
return -;
}
if(depth[x] < depth[y])
swap(x, y);//保证x是比y深的
for ( int i = ; i >= ; --i ) {
if(depth[f[x][i]] >= depth[y]) {//让x跳到和y同一层
ans = min(ans, dis[x][i]);
x = f[x][i];
}
}
if(x == y) {///重合态
return ans;
}
for ( int i = ; i >= ; --i ) {///不重合一起跳
if(f[x][i] != f[y][i]) {//父亲不同要跳一步
ans = min(ans, min(dis[y][i], dis[x][i]));
x = f[x][i], y = f[y][i];
}
}
ans = min(ans, min(dis[x][], dis[y][]));
return ans;///跳完最后一步
} int main()
{
scanf("%d %d", &n, &m);
for ( int i = ; i <= m; ++i ) {
scanf("%d %d %d",&e[i].u, &e[i].v, &e[i].w);
}
join();
for ( int i = ; i <= n; ++i ) {
if(!vis[i]) {
depth[i] = ;
dfs(i);
f[i][] = i;
dis[i][] = 0x3f3f3f3f;
}
}
for ( int i = ; i <= ; ++i ) {
for ( int j = ; j <= n; ++j ) {
f[j][i] = f[f[j][i - ]][i - ];
dis[j][i] = min(dis[j][i - ], dis[f[j][i - ]][i - ]);
//printf("dis[%d][%d]:%d\n",j,i-1,dis[j][i-1]);
//printf("dis[%d][%d]:%d\n\n",fa[j][i-1],i-1,dis[fa[j][i-1]][i-1]);
}
}
int q;
cin >> q;
for ( int i = ; i <= q; ++i ) {
int x, y;
scanf("%d %d", &x, & y);
printf("%d\n",lca(x,y));
}
return ;
}
P1967 货车运输【LCA】【生成树】的更多相关文章
- LUOGU P1967 货车运输(最大生成树+树剖+线段树)
传送门 解题思路 货车所走的路径一定是最大生成树上的路径,所以先跑一个最大生成树,之后就是求一条路径上的最小值,用树剖+线段树,注意图可能不连通.将边权下放到点权上,但x,y路径上的lca的答案不能算 ...
- 洛谷 P1967 货车运输 LCA + 最小生成树
两点之间边权最大值的最小值一定在图的最小生成树中取到. 求出最小生成树,进行倍增即可. Code: #include<cstdio> #include<algorithm> u ...
- P1967 货车运输
P1967 货车运输最大生成树+lca+并查集 #include<iostream> #include<cstdio> #include<queue> #inclu ...
- 洛谷P3379lca,HDU2586,洛谷P1967货车运输,倍增lca,树上倍增
倍增lca板子洛谷P3379 #include<cstdio> struct E { int to,next; }e[]; ],anc[][],log2n,deep[],n,m,s,ne; ...
- 洛谷 P1967 货车运输
洛谷 P1967 货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在 ...
- Luogu P1967 货车运输(Kruskal重构树)
P1967 货车运输 题面 题目描述 \(A\) 国有 \(n\) 座城市,编号从 \(1\) 到 \(n\) ,城市之间有 \(m\) 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 \ ...
- 洛谷P1967货车运输——倍增LCA
题目:https://www.luogu.org/problemnew/show/P1967 就是倍增LCA的裸题,注意一些细节即可. 代码如下: #include<iostream> # ...
- 【杂题总汇】NOIP2013(洛谷P1967) 货车运输
[洛谷P1967] 货车运输 重做NOIP提高组ing... +传送门-洛谷P1967+ ◇ 题目(copy from 洛谷) 题目描述 A国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道 ...
- P1967 货车运输(倍增LCA,生成树)
题目链接: https://www.luogu.org/problemnew/show/P1967 题目描述 A国有n座城市,编号从 1到n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制, ...
- [洛谷 P1967] 货车运输 (最大生成树 lca)
题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多 ...
随机推荐
- 高阶函数及 map、reduce、filter 的实现
博客地址:https://ainyi.com/85 2020 开年国家经历了不少困难,最为凶猛的局势就是新型冠状病毒的蔓延,国务院最终决定春节假期延长至==2 月 2 号==:公司决定 3 - 7 号 ...
- 用Java实现一个简单的DBMS(总结)
时间:2020/1/16 写这个DBMS(说DBMS夸张了,应该是一个控制台程序)的起因是数据库实践老师布置的一个大作业,先贴上GitHub地址: https://github.com/machi12 ...
- Android和servlet通过json完成登录
1.主要过程:Android端发送json数据,servlet接收后解析json数据,通过连接数据库比较并返回json数据到Android端.整个效果: 2.Android端网络连接使用OKHttp开 ...
- Huffman编码和解码
一.Huffman树 定义: 给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径达到最小,这样的二叉树称为最优二叉树,也称为霍夫曼树(Huffman树). 特点: Huffman树 ...
- eclipse新下载,安装和配置
question1 java11没有jre,无法通过eclipse-inst-win64进行安装 solution Windows 7 64bit 安装jdk i586还是jdk x64?jdk x6 ...
- symfony传参,接收参数,twig方法记录
呜呜呜,很烦,让我自己完成一个在线学习系统后端,和前端整合一下,我把接口参数搞了半天(学习symfony太久远),记录一下屈辱历史,以后注意,不然上线了一堆bug,很烦 下面是几种返回的数据的格式 1 ...
- D语言-随机数游戏
由于不会D语言的随机数,干脆core.stdc.stdlib调用stdlib.h 这里mark一下,类型转换是cast(D语言类型) NULL不能用,要用null import std.stdio; ...
- 博客圆美化主题推荐之Slience
博客圆美化主题推荐之Slience 一.前言 本博客美化主题作者为:Esofar,本文仅在教导如何快速把该美化主题应用到自己的博客中,详细部署内容见Silence - 专注于阅读的博客园主题. 二.博 ...
- javascript 防止多次提交或执行(在规定时间段内只允许执行一次) 默认 3000ms
"use strict" class Func{ constructor(){} isRun(id, time){//防止多次提交或执行(在规定时间段内只允许执行一次) 默认 30 ...
- Cacti 抓取数据方式 安装spine
安装好cacti后首先要设置获取数据的方式 Cacti 获取数据的方式有两种,1.监控端的脚本(可以是php, shell, perl 或其他脚本)2.或者 snmp 协议获取. Cacti 会在固定 ...