洛谷 P1967 [NOIP 2013 提高组] 货车运输 题解
原题链接:货车运输
kruskal重构树+LCA做法,树剖不想写
很容易发现原图跑最短路可以解,但是复杂度难以承受,所以考虑如何简化该图。
发现原图边权维护的应该是(u,v)的最小值,并且最优选择是这个最小值最大,所以如果有多条(u,v),只保留最大的没有影响,如果我们维护一棵最大生成树就一定包含(u,v)的最优解。这一部分可以用kruskal重构树。
然后考虑对于这棵树,如何求(u,v)路径上的最小值。
对于一棵树(u,v)是确定的唯一路径,我们可以发现可以把(u,v)拆成两条从LCA(u,v)到u和v的链,最后对它们取min。暴力的做法可以从u,分别上跳直到找到LCA(u,v),时间复杂度O(n),难以承受,所以用倍增LCA,同时维护一个数组st,st[i][j]表示i节点到i的2j辈祖宗节点这条链的min,我们在求min((i,LCA))时,发现可以通过类似LCA算法中将x,y深度拉平的方法,不断上跳使i逼近LCA,期间用每一条短链更新答案,最终求出min((i,LCA)),最后合并两条链答案即可。时间复杂度O(nlogn),可以接受。
AC代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int const N=1e4+10,M=5e4+10;
int p[N];
struct node{
int u,v;
int w;
bool flag;
}tree[M];
int h[N],nx[M],to[M],vl[M],idx=1;
int n,m;
int deep[N],st[N][21],anst[N][21];
bool cmp(node a,node b)
{
return a.w>b.w;
}
int find(int x)
{
if(p[x]==x) return x;
p[x]=find(p[x]);
return p[x];
}
void kruskal(){
for(int i=1;i<=n;i++) p[i]=i;
sort(tree+1,tree+m+1,cmp);
for(int i=1;i<=m;i++)
{
int u=tree[i].u,v=tree[i].v;
int root1=find(u),root2=find(v);
if(root1!=root2)
{
p[root1]=root2;
tree[i].flag=1;
}
}
}
inline void add(int u,int v,int w)
{
to[idx]=v;
nx[idx]=h[u];
vl[idx]=w;
h[u]=idx++;
}
void dfs(int u,int fa)
{
if(u==0) anst[u][0]=0;
else anst[u][0]=fa;
if(u==0) deep[u]=0;
else deep[u]=deep[fa]+1;
//预处理祖先节点,st数组
for(int i=h[u];i;i=nx[i])
{
int v=to[i],w=vl[i];
if(v==fa) continue;
st[v][0]=w;
dfs(v,u);
}
}
void first()//LCA算法的预处理
{
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i<=n;i++)
{
anst[i][j]=anst[anst[i][j-1]][j-1];
}
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
int d=deep[x]-deep[y];
for(int i=0;(1<<i)<=d;i++)
{
if((1<<i) & d)
x=anst[x][i];
}
if(x==y) return x;
for(int i=20;i>=0;i--)
{
if(anst[x][i]!=anst[y][i])
{
x=anst[x][i];
y=anst[y][i];
}
if(anst[x][0]==anst[y][0]) break;
}
return anst[x][0];
}
void RMQ()//预处理st数组
{
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i<=n;i++)
{
st[i][j]=min(st[i][j-1],st[anst[i][j-1]][j-1]);
}
}
}
int check(int fa,int v)//计算子节点到LCA的一条链的min
{
int d=deep[v]-deep[fa];
int mn=INT_MAX;
for(int j=0;(1<<j)<=d;j++)
{
if((1<<j) & d)
{
mn=min(mn,st[v][j]);
v=anst[v][j];
}
}
return mn;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
tree[i].u=u;
tree[i].v=v;
tree[i].w=w;
}
kruskal();
for(int i=1;i<=m;i++)
{
if(!tree[i].flag) continue;
int u=tree[i].u,v=tree[i].v,w=tree[i].w;
add(u,v,w);
add(v,u,w);
}
for(int i=1;i<=n;i++)
{
if(p[i]==i) add(0,i,0);
}//可能是森林,所以需要建立虚拟节点连接,方便DFS
dfs(0,-1);
first();
RMQ();
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
int fa=lca(x,y);
if(fa==0) cout<<-1<<endl;//如果LCA是虚拟节点就说明不连通
else printf("%d\n",min(check(fa,x),check(fa,y)));
}
return 0;
}
码字不易,求赞qwq(转载请标明出处)。
洛谷 P1967 [NOIP 2013 提高组] 货车运输 题解的更多相关文章
- noip 2013 提高组 Day2 部分题解
积木大赛: 之前没有仔细地想,然后就直接暴力一点(骗点分),去扫每一高度,连到一起的个数,于是2组超时 先把暴力程序贴上来(可以当对拍机) #include<iostream> #incl ...
- 洛谷P1082 同余方程 [2012NOIP提高组D2T1] [2017年6月计划 数论06]
P1082 同余方程 题目描述 求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解. 输入输出格式 输入格式: 输入只有一行,包含两个正整数 a, b,用一个空格隔开. 输出格式: 输 ...
- [NOIP2013提高组]货车运输
题目:洛谷P1967.Vijos P1843.codevs3287. 题目大意:有n个城市m条道路,每条道路有一个限重,规定货车运货不能超过限重.有一些询问,问你两个城市之间一次最多能运多少重的货(可 ...
- 洛谷-统计数字-NOIP2007提高组复赛
题目描述 Description 某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*10^9).已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照 ...
- 洛谷-乘积最大-NOIP2000提高组复赛
题目描述 Description 今年是国际数学联盟确定的“2000――世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你 ...
- 洛谷-铺地毯-NOIP2011提高组复赛
题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小到大的顺序平行于 ...
- 洛谷 P2196 挖地雷 & [NOIP1996提高组](搜索,记录路径)
传送门 解题思路 就是暴力!!! 没什么好说的,总之,就是枚举每一个起点,然后暴力算一遍以这个点为起点的所有路径,在算的过程中,只要比目前找到的答案更优,就有可能是最后的答案,于是就把路径更新一遍,保 ...
- noip 2013 提高组 day1
1.转圈游戏: 解析部分略,快速幂就可以过 Code: #include<iostream> #include<fstream> using namespace std; if ...
- NOIP 2013 提高组 洛谷P1967 货车运输 (Kruskal重构树)
题目: A 国有 nn 座城市,编号从 11 到 nn,城市之间有 mm 条双向道路.每一条道路对车辆都有重量限制,简称限重. 现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情 ...
- NOIP 2013 提高组 day1 T2 火柴排队 归并 逆序对
描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:∑i=1n(ai−bi)2∑i=1n(ai−bi) ...
随机推荐
- win10系统出现虚拟内存不足的问题
最近有电脑基地的用户发现,用windows10系统的电脑物理内存已经16G,不过在使用程序时还是会弹出虚拟内存不足,将关闭**程序的问题,而系统也变的很卡,但是,出现虚拟内存不足如何设置呢?下面技术员 ...
- MySQL 22 MySQL有哪些“饮鸩止渴”提高性能的方法?
有时候,在业务高峰期,生产环境的MySQL压力太大,没法正常响应,需要短期内.临时性地提升一些性能.本文就来讲讲一些临时方法,并着重说它们可能存在的风险. 短连接风暴 正常的短连接模式是连接到数据库后 ...
- 从git仓库下载 单个文件或者文件夹
转载自:https://www.cnblogs.com/yaolaoer/p/14564985.html 下载单个文件到压缩包:aab.zipgit archive --remote=ssh://ge ...
- 亚马逊AI模型评估产品评论中的实用建议有效性
产品评论中的实用建议验证模型 电子商务网站的产品评论是消费者购物决策的重要参考,其中常包含"首次使用相机前充电8小时"等非显而易见的实用建议(product tips).为帮助消费 ...
- 【转】-Java反射
Java 反射由浅入深 | 进阶必备 原文链接 本博文主要记录我学习 Java 反射(reflect)的一点心得,在了解反射之前,你应该先了解 Java 中的 Class 类,如果你不是很了解,可以先 ...
- leedcode 827. 最大人工岛 (洪水填充)
测试链接:https://leetcode.cn/problems/making-a-large-island/ 思路: 先用洪水填充给每个岛屿进行编号,以便最后答案更新区分,设置一个used[]数组 ...
- Js克隆对象
Js克隆对象 1 浅复制 具体方法 // 数组 Array.prototype.slice const oldArr = new Array(100).fill(null).map(() => ...
- 15分钟速通yolo12,从环境搭建到推理图片,最后训练自己的数据集
项目演示视频: https://www.bilibili.com/video/BV127YXz4Eto/ 1 环境搭建 1.1 python安装 python我们这里使用了3.10,python的 ...
- Maven 出现问题及解决方案
问题描述 相信使用过 Maven 的同学,偶尔会遇到莫名其妙的问题,就是 pom.xml 添加的依赖,老是显示红色的波浪线,而且无论怎么刷新都无法消除. 原因分析 出现这种情况多半是由于网络传输原因( ...
- ASCII字符画转ASCII码——C语言输出使用
ASCII字符画转ASCII码--C语言输出使用 首先,打开下面的网站,生成你所需要的ASCII画 Text to ASCII Art Generator (TAAG) (patorjk.com) 把 ...