[noip2013]货车运输(kruskal + 树上倍增)
描述
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
格式
输入格式
第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。
输出格式
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。
样例1
样例输入1
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
样例输出1
3
-1
3
限制
每个测试点1s。
提示
对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000;
对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000;
对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。
因为货车要运输最大货物,必须在整张图的最大生成树上选边,可以想到kruskal算法,但此时若要对每一个询问进行一次遍历的话需要 O(mn) 的时间复杂度,那么就需要把答案预先处理出来。
RMQ问题的ST算法 是用 d(i, j) 表示 从 i 开始 长度为 2^j 的一段元素之间的最小值
那么 d(i, j) = min{d(i ,j - 1), d(i + 2 ^ (j - 1), j - 1)}; 从 i 开始长度为 2^j 的最小值 = min{从 i 开始长度为2^(j - 1) 的一段元素的最小值, 从i + 2^(j - 1) + 1开始长度为2^(j - 1)的最小值};
这个题在处理时同样可以借鉴这种思路,这个题在树上(我也不知道在说啥),所以:
以 f[i][j] 表示第i个结点的第2^j个祖先是哪个点,那么 f[i][0] 为第i个节点的父亲。
以 g[i][j] 表示第i个结点到 f[i][j](第i个结点的第2^j个祖先) 的最短距离,那么 g[i][0] 表示第i个节点到自己父亲的(最短)距离。
转移可以模仿ST算法:
f[i][j] = f[ f[i][j - 1] ][j - 1]; 第i个点的第2^j个祖先 = 【第i个点第2^(j - 1)的祖先】 的 【第2^(j - 1)的祖先】
g[i][j] = min(g[i][j - 1], g[ f[i][j - 1] ][j - 1]); 第i个结点到 自己的第2^j个祖先 的最短距离 = min{第i个结点到 自己的第 2^(j - 1) 个祖先 的最短距离,【 第i个结点的第2^(j - 1)个祖先】到 【自己的第2^(j - 1)个祖先】 的最短距离}
【】只是为了帮助断句。。。
之后若要查询(x, y)的最短距离只需查询 min{(x, pos)的最短距离,(y, pos)的最短距离} pos为x,y的最近公共祖先
那么借用dfs的思路即可预处理整张图得到f和g
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
struct node {
int x, y, val;
}edge[];
int n, m, cnt;
bool cmp(node a, node b) { return a.val > b.val; }
int u[], v[], next[], first[], w[];
int in[], father[], hi[];
void addedge(int st, int end, int value)
{
u[++cnt] = st, v[cnt] = end, w[cnt] = value;
next[cnt] = first[st];
first[st] = cnt;
}
int getfather(int x) { return father[x] == x ? x : father[x] = getfather(father[x]); }
void kruskal()
{
int count;
for (int i = ; i <= n; i++) father[i] = i;
for (int i = ; i <= m; i++) {
int st = edge[i].x, end = edge[i].y;
int fa = getfather(father[st]), fb = getfather(father[end]);
if (fa != fb) {
addedge(st, end, edge[i].val);
addedge(end, st, edge[i].val);
father[fb] = fa;
count++;
if (count == n - ) return;
}
}
}
int vis[];
int fa[][], Min[][];
void dfs(int o)
{
vis[o] = ;
for (int i = ; i <= ; i++) {
if (hi[o] < ( << i)) break;
fa[o][i] = fa[fa[o][i - ]][i - ];
Min[o][i] = min(Min[o][i - ], Min[fa[o][i - ]][i - ]);
}
for (int i = first[o]; i; i = next[i]) {
int end = v[i];
if (!vis[end]) {
fa[end][] = o;
Min[end][] = w[i];
hi[end] = hi[o] + ;
dfs(end);
}
}
}
int lca(int l, int r)
{
if (hi[l] < hi[r]) swap(l, r);
int t = hi[l] - hi[r];
for (int i = ; i <= ; i++) {
if (( << i) & t) l = fa[l][i];
}
for (int i = ; i >= ; i--) {
if (fa[l][i] != fa[r][i]) {
l = fa[l][i], r = fa[r][i];
}
}
if (l == r) return l;
return fa[l][];
}
int ask(int l, int r)
{
int ret = 0x3f3f3f3f;
int t = hi[l] - hi[r];
for (int i = ; i <= ; i++) {
if (t & ( << i)) {
ret = min(ret, Min[l][i]);
l = fa[l][i];
}
}
return ret;
}
int main()
{
memset(Min, 0x3f3f3f3f, sizeof(Min));
scanf("%d%d", &n, &m);
for (int i = ; i <= m; i++) {
scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].val);
}
sort(edge + , edge + + m, cmp);
kruskal();
for (int i = ; i <= n; i++) if (!vis[i]) dfs(i);
int t, l, r;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &l, &r);
if (getfather(father[l]) != getfather(father[r])) printf("-1\n");
else {
int pos = lca(l, r);
printf("%d\n", min(ask(l, pos), ask(r, pos)));
}
}
return ;
}
变量名不好起啊。
[noip2013]货车运输(kruskal + 树上倍增)的更多相关文章
- NOIP2013 货车运输(最大生成树,倍增)
NOIP2013 货车运输(最大生成树,倍增) A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道 ...
- [Luogu 1967] NOIP2013 货车运输
[Luogu 1967] NOIP2013 货车运输 一年多前令我十分头大的老题终于可以随手切掉了- 然而我这码风又变毒瘤了,我也很绝望. 看着一年前不带类不加空格不空行的清纯码风啊,时光也好像回去了 ...
- NOIP2013 货车运输 (最大生成树+树上倍增LCA)
死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...
- Luogu1967 NOIP2013 货车运输 最大生成树、倍增
传送门 题意:给出一个$N$个节点.$M$条边的图,$Q$次询问,每一次询问两个点之间的所有可行路径中经过的边的边权的最小值中的最大值.$N \leq 10000 , M \leq 50000 , Q ...
- NOIp2013 货车运输 By cellur925
题目传送门 A 国有 n 座城市,编号从 1 到 n ,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重. 现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下 ...
- NOIP2013 货车运输
3.货车运输 (truck.cpp/c/pas) [问题描述] A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货 ...
- Luogu P1967 货车运输(Kruskal重构树)
P1967 货车运输 题面 题目描述 \(A\) 国有 \(n\) 座城市,编号从 \(1\) 到 \(n\) ,城市之间有 \(m\) 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 \ ...
- Codevs3278[NOIP2013]货车运输
3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description A 国有 ...
- 【洛谷P1967】[NOIP2013]货车运输
货车运输 题目链接 显然,从一点走到另一点的路径中,最小值最大的路径一定在它的最大生成树上 所以要先求出最大生成树,再在生成树上找最近公共祖先,同时求出最小值. #include<iostrea ...
随机推荐
- CodeForces 696A Lorenzo Von Matterhorn (LCA + map)
方法:求出最近公共祖先,使用map给他们计数,注意深度的求法. 代码如下: #include<iostream> #include<cstdio> #include<ma ...
- Java的SSH框架
SSH 为 struts+spring+hibernate的一个集成框架,是目前较流行的一种Web应用程序开源框架. 1.业务流程 集成SSH框架的系统从职责上分为四层:表示层.业务逻辑层.数据 ...
- PHP字节格式化
/** * 容量转换 * @param string $value 字节数值 * @return string */function GBKB($value) { $size = ($value &g ...
- IPoint Interface接口
Description A Point is a zero-dimensional object that represents a specific (X, Y) location in a the ...
- PL/SQL developer 管理多套数据库
PL/SQL developer 管理多套数据库,作为一个统一的接口平台,连接多套数据库. 1.. 1.类SQL PLUS窗口:File->New->Command Window,这个类似 ...
- hihocoder 网络流二·最大流最小割定理
网络流二·最大流最小割定理 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么? ...
- js选择一个选项 跳出另一个选项 跳出一个输入框
跳出输入框 <script language="javascript"> function $(obj){return document.getElementById( ...
- Myeclipse8.5中svn插件安装方法总结
[转]http://lwcheng1985.iteye.com/blog/696143 有改动 方法一:在线安装 1.打开HELP->MyEclipse Configuration Cent ...
- unity3d 多人寻路堵塞堆叠问题
使用unity提供的NavMeshAgent寻路,当有多个agent一起寻路时总会出现堵塞堆叠的问题. 本人使用了一个非常粗劣简单的方案解决此问题,当然跟魔兽的寻路完全没得比,但保证有比较好的性能,且 ...
- wex5 实战 微信6位数字密码输入设计
微信支付使用是6位数字输入,用wex5能不能制作这种效果呢? 答案是肯定的. 根据网上提供的数字插件,研究源码后,与wex5进行整后修改,便于利用wex5框架优势. 一 效果演示: 弹出密码框 输入 ...