洛谷题目链接:[NOI2018]归程

因为题面复制过来有点炸格式,所以要看题目就点一下链接吧\(qwq\)


题意: 在一张无向图上,每一条边都有一个长度和海拔高度,小\(Y\)的家在\(1\)节点,并且他有一部车,车只能在海拔高度大于降水量的道路上行驶,如果某一条边的海拔高度小于等于降水量,那么小\(Y\)就必须下车步行,现在有\(q\)次询问,每次询问从目标点到\(1\)要步行的最短距离.强制在线.

题解: 这题我采用的做法是kruskal重构树.

可能大家对kruskal重构树并不是很熟悉,但是想必都会kruskal.我们先分析一下题目有哪些性质:

  1. 降雨量越少,可以走的边越多,从出发点开始可以到达的点越多.
  2. 下车后要到达\(1\)号节点,且必须步行,则选择最短路走.

根据性质\(1\),我们可以知道,每次询问的起点其实是一个集合,且在降水量越少的时候集合内的元素越多.

既然有这样的性质,那么我们可以考虑一下这题的离线做法:我们可以先预处理一下\(1\)到所有点的最短路,再将询问的降水量从大到小排个序,这样可以保证每次起点集合是在不断变大或不变的.

然后建出一颗最大生成树(以降雨量为关键字).这样虽然无法保证从起点集合中一个点到\(1\)号点的距离最小,但是可以保证起点集合尽量大.

每次询问前将所有海拔高度大于此时降雨量的边的顶点所在的并查集合并,这样就可以维护出一个起点集合.同时再在并查集中维护到达\(1\)节点的最短路,这样在查询的时候就可以保证距离是最小的了.

这样的复杂度是\(O(mlogm+k*n)\)的(主要来自于对边的排序和并查集合并的常数.


但是因为题目对查询强制在线,所以我们就必须采用一个更高效的方式来维护这个起点集合.

这时候就引入了我们的kruskal重构树.

做法与离线做法大概相似,但是在维护集合合并关系的时候并不是直接采用数组记录,而是通过开一个节点构出一颗二叉树的方式来维护.

我们还是先预处理最短路,然后将边按照海拔高度排序,然后就开始构kruskal重构树了.

在合并一条边的起点\(st\)和终点\(ed\)的时候,朴素做法是将两个点所在的并查集合并,这里我们新开一个节点,并将\(st\)和\(ed\)的父亲指向这个新节点\(node\),并将这条边的海拔计入这个点,同时维护一个并查集,将\(st\),\(ed\)和\(node\)所在的并查集合并.

那么这样合并好的一颗最小生成树,表示在重构树上就是一颗二叉树.并且它具有这样的性质:

  1. 节点记录的海拔高度是一个二叉堆.
  2. 某个节点所在的子树中所有的节点都是在同一个集合中的.
  3. 在原图上的边权信息以点权的方式存入了重构树中.

既然如此,我们就可以在重构树上跑倍增了(因为节点上的海拔高度是单调递增的),并且我们可以在构树的时候将这个节点的子树中的节点距离\(1\)的最小值记录下来,这样在倍增找到起点集合的最大范围后可以\(O(1)\)回答这个集合到\(1\)的最短距离.

分析一下空间复杂度.因为每次合并两个点,集合数量都会减少\(1\),所以最多会新建\(n\)个节点.所以有关新建节点的数组都要开两倍空间.

到这里其实就做完了,对于这题有些小细节,比如不能跑\(SPFA\),在处理倍增数组的时候要将新建立的点也加入倍增的预处理中.

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 300000+5;
  4. const int M = 400000+5;
  5. const int inf = 2147483647;
  6. int T, n, m, q, k, s, ecnt = 0, last[N], lans = 0;
  7. int dist[N], vis[N];
  8. int fa[N*2], cnt = 0, mn[N*2], gup[N*2][26], val[N*2];
  9. struct edge{
  10. int to, nex, rain, w;
  11. }e[M*2];
  12. struct EDGE{
  13. int st, ed, w, rain;
  14. }a[M];
  15. bool cmpe(EDGE a, EDGE b){
  16. return a.rain > b.rain;
  17. }
  18. struct node{
  19. int dis, id;
  20. bool operator < (const node &a) const{
  21. return dis > a.dis;
  22. }
  23. };
  24. int gi(){
  25. int ans = 0, f = 1; char i = getchar();
  26. while(i<'0' || i>'9'){ if(i == '-') f = -1; i = getchar(); }
  27. while(i>='0' && i<='9') ans = ans*10+i-'0', i = getchar();
  28. return ans * f;
  29. }
  30. void clear(){
  31. memset(last, 0, sizeof(last)), ecnt = 0, cnt = n, lans = 0;
  32. memset(dist, 127/3, sizeof(dist)), memset(vis, 0, sizeof(vis));
  33. memset(gup, 0, sizeof(gup));
  34. for(int i=1;i<=n;i++) fa[i] = i;
  35. for(int i=1;i<=n;i++) val[i] = 0;
  36. for(int i=n+1;i<=n+n;i++) mn[i] = inf;
  37. }
  38. void add(int x, int y, int z, int w){
  39. e[++ecnt].to = y, e[ecnt].w = w, e[ecnt].rain = z;
  40. e[ecnt].nex = last[x], last[x] = ecnt;
  41. }
  42. int find(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]); }
  43. void dijkstra(){
  44. priority_queue <node> q; q.push((node){ 0, 1 }), dist[1] = 0;
  45. while(!q.empty()){
  46. node x = q.top(); q.pop();
  47. if(vis[x.id]) continue; vis[x.id] = 1;
  48. for(int to, i=last[x.id];i;i=e[i].nex){
  49. to = e[i].to;
  50. if(dist[to] > x.dis+e[i].w){
  51. dist[to] = x.dis+e[i].w;
  52. q.push((node){ dist[to], to });
  53. }
  54. }
  55. }
  56. }
  57. void init(){
  58. for(int j=1;j<=20;j++)
  59. for(int i=1;i<=cnt;i++) gup[i][j] = gup[gup[i][j-1]][j-1];
  60. }
  61. int solve(int x, int lim){
  62. for(int i=20;i>=0;i--)
  63. if(gup[x][i] && val[gup[x][i]] > lim) x = gup[x][i];
  64. return mn[x];
  65. }
  66. int main(){
  67. ios::sync_with_stdio(false);
  68. int x, y; T = gi();
  69. while(T--){
  70. n = gi(), m = gi(); clear();
  71. for(int i=1;i<=m;i++){
  72. a[i].st = gi(), a[i].ed = gi(), a[i].w = gi(), a[i].rain = gi();
  73. add(a[i].st, a[i].ed, a[i].rain, a[i].w);
  74. add(a[i].ed, a[i].st, a[i].rain, a[i].w);
  75. }
  76. sort(a+1, a+m+1, cmpe), dijkstra();
  77. for(int i=1;i<=n;i++) mn[i] = dist[i];
  78. for(int i=1;i<=m;i++){
  79. int r1 = find(a[i].st), r2 = find(a[i].ed);
  80. if(r1 != r2){
  81. gup[r1][0] = gup[r2][0] = fa[r1] = fa[r2] = ++cnt;
  82. fa[cnt] = cnt, mn[cnt] = min(mn[r1], mn[r2]), val[cnt] = a[i].rain;
  83. }
  84. }
  85. init(), q = gi(), k = gi(), s = gi();
  86. for(int i=1;i<=q;i++){
  87. x = gi(), y = gi(), x = (x+k*lans-1) % n + 1, y = (y+k*lans) % (s+1);
  88. cout << (lans = solve(x, y)) << endl;
  89. }
  90. }
  91. return 0;
  92. }

[洛谷P4768] [NOI2018]归程 (kruskal重构树模板讲解)的更多相关文章

  1. 洛谷P4768 [NOI2018]归程(Kruskal重构树)

    题意 直接看题目吧,不好描述 Sol 考虑暴力做法 首先预处理出从$1$到每个节点的最短路, 对于每次询问,暴力的从这个点BFS,从能走到的点里面取$min$ 考虑如何优化,这里要用到Kruskal重 ...

  2. 洛谷$P4768\ [NOI2018]$归程 $kruscal$重构树

    正解:$kruscal$重构树 解题报告: 传送门$QwQ$ 语文不好选手没有人权$TT$连题目都看不懂真的要哭了$kk$ 所以先放个题目大意?就说给定一个$n$个点,$m$条边的图,每条边有长度和海 ...

  3. [NOI2018]归程 kruskal重构树

    [NOI2018]归程 LG传送门 kruskal重构树模板题. 另一篇文章里有关于kruskal重构树更详细的介绍和更板子的题目. 题意懒得说了,这题的关键在于快速找出从查询的点出发能到达的点(即经 ...

  4. LOJ.2718.[NOI2018]归程(Kruskal重构树 倍增)

    LOJ2718 BZOJ5415 洛谷P4768 Rank3+Rank1无压力 BZOJ最初还不是一道权限题... Update 2019.1.5 UOJ上被hack了....好像是纯一条链的数据过不 ...

  5. 洛谷 P4768 [NOI2018]归程

    洛谷 361行代码的由来 数据分治大发好啊- NOI的签到题,可怜我在家打了一下午才搞了80分. 正解应该是kruskal重构树或排序+可持久化并查集. 我就分点来讲暴力80分做法吧(毕竟正解我也没太 ...

  6. BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra

    题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l,a 描述一条边的长度.海 ...

  7. 洛谷P4768 [NOI2018]归程 [可持久化并查集,Dijkstra]

    题目传送门 归程 格式难调,题面就不放了. 分析: 之前同步赛的时候反正就一脸懵逼,然后场场暴力大战,现在呢,还是不会$Kruskal$重构树,于是就拿可持久化并查集做. 但是之前做可持久化并查集的时 ...

  8. BZOJ 5415: [Noi2018]归程(kruskal重构树)

    解题思路 \(NOI2018\)的\(Day1\) \(T1\),当时打网络赛的时候不会做.学了一下\(kruskal\)重构树后发现问题迎刃而解了.根据\(kruskal\)的性质,如果要找从\(u ...

  9. 洛谷P4197 Peaks (Kruskal重构树)

    读题,只经过困难值小于等于x的路径,容易想到用Kruskal重构树:又要查询第k高的山峰,我们选择用主席树求解. 先做一棵重构树,跑一遍dfs,重构树中每一个非叶子节点对应一段区间,我们开range[ ...

随机推荐

  1. wf效能分析

    听从了老师的建议我请教了其他的同学,修改了代码实现了功能四,以下是我的效能测试: 1.采用ptime.exe测试的3次截图 可以看到的是三次执行时间分别为:1.449秒:0.915秒:0.871秒,取 ...

  2. c++ string需要注意的地方

    There are multiple answers based on what you are doing with the string. 1) Using the string as an id ...

  3. java多线程三之线程协作与通信实例

    多线程的难点主要就是多线程通信协作这一块了,前面笔记二中提到了常见的同步方法,这里主要是进行实例学习了,今天总结了一下3个实例: 1.银行存款与提款多线程实现,使用Lock锁和条件Condition. ...

  4. TCP系列35—窗口管理&流控—9、紧急机制

    一.概述 我们在最开始介绍TCP头结构的时候,里面有个URG的标志位,还有一个Urgent Pointer的16bits字段.当URG标志位有效的时候,Urgent Poinert用来指示紧急数据的相 ...

  5. HDU 2115 I Love This Game

    http://acm.hdu.edu.cn/showproblem.php?pid=2115 Problem Description Do you like playing basketball ? ...

  6. 【bzoj3754】Tree之最小方差树 最小生成树

    题目描述 给出一张无向图,求它的一棵生成树,使得选出的所有边的方差最小.输出这个最小方差. 输入 第一行两个正整数N,M 接下来M行,每行三个正整数Ui,Vi,Ci N<=100,M<=2 ...

  7. jQuery全选反选实例

    1. $('#tb:checkbox').each(function(){ 每次都会执行 全选-取消操作,注意$('#tb :checkbox').prop('checked',true); tb后面 ...

  8. POJ3384:Feng Shui——题解

    http://poj.org/problem?id=3384 题目大意:给一个顺时针序的多边形,求在里面放半径为r的两个圆使得两圆覆盖的面积最大,求出这样的圆的坐标. ———————————————— ...

  9. 实验五 TCP传输及加解密

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计                         班级:1353            姓名:陈巧然     ...

  10. mysql jdbc 连接url

    jdbc url连接地址格式: jdbc:mysql://[host][,failoverhost...][:port]/[database] [?propertyName1][=propertyVa ...