这几天把13年的提高做了,最后两道题参考了网上许多代码,最后终于改出来了,这里是day1最后一题。

描述

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。

样例

输入

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

输出

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。

来源

NOIP 2013 提高组 Day 1


先是不知道怎么做,spfa乱搞,dijikstra乱搞,用floyed写了个对拍,对出来没问题,结果交上去T了 85%。。。
下来看了一下,先了求最大生成树,再spfa乱搞,又交上去,只T了40%。
后来看了某位大大的倍增求lca(最近公共祖先)


有了lca,做出来就很轻松了,我们只需要先跑一边kruskal,把最大生成树求出来,然后求出1点到 lca 的最小值,再求出 2到 lca的最小值,然后再取一个最小值就出来了。

那么,现在 问题就来了

1、如何建树

2、如何找lca

3、如何找最小值


一、如何建树

kruskal跑一边,把最大生成树需要使用的边mark,但一定要注意,不能和直接使用最大生成树,因为跑的时候我们用的是并查集,树早就长得和原来不一样了。
跑完kruskal再跑一边dfs就可以把树建出来,同时把每个节点的深度求出来,但同时需要主要,每个节点还需保存它的根节点,因为可能不只存在一棵树


二、如何找lca

找lca是这里的核心问题,如果直接向上按着父节点跳就和spfa没什么区别了,复杂度没有优化,就要用倍增来找,一次向上跳2^i个节点,这样原来的O(n)就优化成O(log n)了
于是建立倍增数组fa[i][j],表示j这个节点向上的第2^i个是那里
同时很容易得出递推式fa[i][j]=fa[i-1][fa[i-1][j]]
fa[i][j]等于j向上移2^(i-1),再向上移2^(i-1)
于是:

void bz()//倍增
{for(int i=1;i<=14;i++)for(int j=1;j<=n;j++)fa[i][j]=fa[i-1][fa[i-1][j]];
}

建立完倍增数组判断就可以以log的速度进行了,先判断两个节点是否在一棵树,再将它们的深度上移成一样,在尽量同步上移但使两个节点不一样,这是两个节点就都在lca下面一个了,再上一一个就是lca了。


三、如何找最小值

最小值我们同样用倍增,用minax[i][j](因为先跑了一个最大生成树,所以实际上是最小值的最大值,所以我叫它minax)表示表示j这个节点向上的2^i个这一段的最小值是什么,递推式一样,此处不再赘述

下面是我写的代码,仅提供参考


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<vector>
#define N 10005
#define M 100005
#define INF 2147480000using namespace std;int n,m,q,t;
int fa[15][N],minax[15][N],depth[N],tfa[N],unuse[M],flag[N];struct Edge
{int from,to,d;
}e[M];vector<int> a[N];
bool com (const Edge &a,const Edge &b)
{return a.d>b.d;
}int F(int x)//并查集
{return x==tfa[x]?x:tfa[x]=F(tfa[x]);
}void kruskal()
{for(int i=1;i<=n;i++)tfa[i]=i;for(int i=1;i<=2*m;i++){int x=F(e[i].to),y=F(e[i].from);if(x!=y){tfa[x]=y;}else unuse[i]=1;}
}void dfs(int x)//找深度 建树
{if(!a[x].empty())for(int i=0;i<a[x].size();i++){int o=a[x][i];int t=e[o].to+e[o].from-x;if(!flag[t]){flag[t]=1;depth[t]=depth[x]+1;fa[0][t]=x;minax[0][t]=e[o].d;dfs(t);}}
}void bz()//倍增
{for(int i=1;i<=14;i++)for(int j=1;j<=n;j++){fa[i][j]=fa[i-1][fa[i-1][j]];minax[i][j]=min(minax[i-1][j],minax[i-1][fa[i-1][j]]);}}int lca(int s,int v)//找最近公共祖先,并求出最小值
{int t1=INF,t2=INF;//两边子树最小值if(F(s)!=F(v))return -1;//判断是否连通 if(depth[v]>depth[s])//保证s在v下面swap(s,v);int dh=depth[s]-depth[v];for(int i=0;i<=14;i++)//使两个点深度相同 {if(1<<i&dh)//位运算 {t1=min(t1,minax[i][s]);s=fa[i][s]; }} if (s==v) return t1; //判断是否已经满足 for(int i=14;i>=0;i--){if(fa[i][s]!=fa[i][v]){t1=min(t1,minax[i][s]);t2=min(t2,minax[i][v]);s=fa[i][s];v=fa[i][v];}}//此时两点都在最近公共祖先的下面,只需再向上走一步 t1=min(t1,minax[0][s]);t2=min(t2,minax[0][v]);return min(t1,t2);
} int main()
{#ifdef LOCAL freopen("truck.in","r",stdin);freopen("truck.out","w",stdout);#else#endifcin>>n>>m;for(int i=1;i<=m;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);e[i*2].from=x;e[i*2].to=y;e[i*2].d=z;e[i*2-1].from=y;e[i*2-1].to=x;e[i*2-1].d=z;}sort(e+1,e+2*m+1,com);kruskal();for(int i=1;i<=2*m;i++)//扫一遍 存使用过的边 if(!unuse[i]){a[e[i].from].push_back(i);a[e[i].to].push_back(i);}for(int i=1;i<=n;i++)if(!depth[i]){int tf=F(i);depth[tf]=1;dfs(tf);        //dfs建树 }bz();cin>>q;for(int i=1;i<=q;i++){int x,y;scanf("%d%d",&x,&y);cout<<lca(x,y)<<'\n';}return 0;
}

如果有什么问题,或错误,请在评论区提出,谢谢。

【noip】【lca】火车运输 倍增相关推荐

  1. [最大生成树Kruskal/倍增LCA] 火车运输 洛谷P1967

    题目描述 AA 国有 nn 座城市,编号从 11 到 nn ,城市之间有 mm 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重 ...

  2. 对LCA、树上倍增、树链剖分(重链剖分长链剖分)和LCT(Link-Cut Tree)的学习

    LCA what is LCA & what can LCA do LCA(Lowest Common Ancestors),即最近公共祖先 在一棵树上,两个节点的深度最浅的公共祖先就是 L ...

  3. 贪心--2016cqround4火车运输

    P3827火车运输 时间限制 : - MS   空间限制 : 265536 KB   评测说明 : 1000ms 问题描述 ByteLand火车站(编号0)每天都要发往全国各地N列客运火车,编号1 N ...

  4. 【题】【贪心】NKOJ3827 火车运输

    NKOJ3827 火车运输 时间限制 : - MS 空间限制 : 265536 KB 评测说明 : 1000ms 问题描述 ByteLand火车站(编号0)每天都要发往全国各地N列客运火车,编号1 N ...

  5. 洛谷1967 火车运输 kruskal求最大生成树 倍增LCA维护最小值

    传送门 其实NOIP某些年的第三题也并不是很难嘛... 题目分析: 题目中要求求出某两点之间可以运输的最大重量,也就是这两个点的某条路径上边权最小的边的权值的最大值 很显然,题目中的运输最大重量与选择 ...

  6. [NOIP2013提高组] CODEVS 3287 火车运输(MST+LCA)

    一开始觉得是网络流..仔细一看应该是最短路,再看数据范围..呵呵不会写...这道题是最大生成树+最近公共祖先.第一次写..表示各种乱.. 因为要求运输货物质量最大,所以路径一定是在最大生成树上的.然后 ...

  7. NOIP2013 D1T3 货车运输 倍增LCA OR 并查集按秩合并

    思路: Kruskal求最大生成树+倍增LCA // by SiriusRen #include <cstdio> #include <cstring> #include &l ...

  8. 火车运输[NOIP 2013 提高组 Day 1]

    https://vijos.org/p/1843 本题 kruskal+倍增lca WA了三次 T_T 总结出一些注意事项: 1. 一定要想明白每一部分是求最大值还是最小值!!!(WA 1) 2. 注 ...

  9. NKOI 2495 火车运输

    [NOIP2013-D1T3]货车运输 Time Limit:10000MS  Memory Limit:128000K Total Submit:95 Accepted:57 Case Time L ...

最新文章

  1. 聊聊spring cloud的LoadBalancerAutoConfiguration
  2. 在Spring中使用多个动态缓存
  3. mobx中跟新了数据视图没变化_【第1781期】MobX 简明教程
  4. leetcode1207. 独一无二的出现次数
  5. 使用 Visual Leak Detector 检测内存泄漏
  6. 计算机如何建筑材料结合所学知识,《技术与设计2》第三、四单元检测试卷
  7. Linux入门命令解释(1)
  8. ssm框架整合springSecurity
  9. 发送导频信号用到的 matlab function
  10. 织梦dedecms调用热门搜索关键词的方法
  11. 关于芯片最高工作频率的计算
  12. 打开SharePoint时遇到“Server error: http://go.microsoft.com/fwlink?LinkID=96177”
  13. 为什么有些大公司的技术弱爆了?
  14. 通用电气公司要破产?美国慌不慌?
  15. excel输入公式显示公式_显示Excel公式而不是结果
  16. PS教程:紫色光晕效果实现
  17. 论文对图片与什么要求呢?
  18. jetson emmc版本刷机。
  19. AdminLTE模板框架
  20. GeckoDriver 国内镜像源加速下载

热门文章

  1. 【集训队作业2018】青春猪头少年不会梦到兔女郎学姐(容斥)(分治FFT)
  2. php php_zip.dll,php_zip.dll,下载,简介,描述,修复,等相关问题一站搞定_DLL之家
  3. AT+CPSMS/AT+CEDRXS - NB网络PSM 和 eDRX配置参数说明
  4. 1005.E. Maximize Sum Of Array After K Negations
  5. 获取安卓应用包名和入口 Activity
  6. openpyxl版本问题
  7. BRIEF描述子原理、 python源码实现及基于opencv实现
  8. 奋斗吧,程序员——第四十七章 所谓伊人,在水一方
  9. 可恶啊,被他用责任链给装到了
  10. MySQL 设置 创建时间 和 更新时间