题面在这里就不放了。

同步赛在做这个题的时候,心里有点纠结,很容易想到离线的做法,将边和询问一起按水位线排序,模拟水位下降,维护当前的各个联通块中距离$1$最近的距离,每次遇到询问时输出所在联通块的信息。

离线的思路对满分做法有一定的启发性,很容易想到将并查集持久化一下就能支持在线了。

但是这个是两个$log$的,有卡常的风险也不是很方便写。

当时思考了一下就快速写完离线做法就去做其他题了。

对于这道题,有一个更好的做法:Kruskal重构树。

事实上如果你了解这个东西,那你就能很快的给出解,那仅此以这道题作为学习Kruskal重构树的例子。

先给出一个经典的模型:

  • 给定一张无向图,每次询问两点之间所有简单路径中最大边权的最小值。

一个常规的做法就是建出最小生成树,答案就是树上路径的最大边权,正确性显然。

当然也可以用我们要讲的Kruskal重构树来解决,算法虽不同,思想类似。

Kruskal中我们连接两个联通块(子树)时直接用一条边将对应的两个点相连,但在Kruskal重构树中,我们先建一个虚点作为两个子树的树上父亲,让两个联通块分别与该点相连,注意的是要维护并查集合并时的有序性。

我们称新建的虚点为方点,代表了原图中的一条边,原图中的点为圆点,则该树有一些优雅的性质:

  1. 这是一颗二叉树,并且相当于一个堆,因为边是有顺序合并的。
  2. 最小生成树上路径的边权信息转化成了点权信息。

那么回顾刚刚的那个模型,每个询问就相当于回答Kruskal重构树上两点$lca$的权值。

最后在回来看这道题,就显得十分轻松了。

我们把每条边按照水位线从高到低依次插入,可以发现每次规定一个水位下限,车子能走的范围对应了Kruskal重构树上的一棵子树,那么每次只要倍增找到最紧的那个限制的点就可以了。

  1 #include <cstdio>
  2 #include <queue>
  3 #include <cstring>
  4 #include <algorithm>
  5
  6 typedef long long LL;
  7 const int N = 600005, INF = 2e9 + 7, LOG = 21;
  8
  9 int tc, n, m, Qi, k, s;
 10 int dis[N], flg[N], val[N], mdi[N], gr[LOG][N];
 11 std::priority_queue<std::pair<int, int> > Q;
 12
 13 inline void Read(int &x) {
 14     x = 0; static char c;
 15     for (c = getchar(); c < '0' || c > '9'; c = getchar());
 16     for (; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
 17 }
 18
 19 struct Edge {
 20     int u, v, a;
 21     inline friend bool operator < (Edge a, Edge b) {
 22         return a.a > b.a;
 23     }
 24 } e[N];
 25
 26 int yun, las[N], to[N << 1], pre[N << 1], wi[N << 1];
 27 inline void Add(int a, int b, int c = 0) {
 28     to[++yun] = b; wi[yun] = c; pre[yun] = las[a]; las[a] = yun;
 29 }
 30 void Gragh_clear() {
 31     memset(gr, 0, sizeof gr);
 32     memset(las, 0, sizeof las);
 33     yun = 0;
 34 }
 35
 36 namespace DSU {
 37     int fa[N];
 38     void Init() {
 39         for (int i = 1; i <= n + m; ++i) {
 40             fa[i] = i;
 41             if (i <= n) mdi[i] = dis[i], val[i] = -1;
 42         }
 43     }
 44     int Seek(int x) {
 45         return (x == fa[x])? (x) : (fa[x] = Seek(fa[x]));
 46     }
 47     void Merge(int x, int y) {
 48         fa[Seek(y)] = x;
 49     }
 50 }
 51
 52 void Dij() {
 53     for (int i = 1; i <= n; ++i) {
 54         dis[i] = INF; flg[i] = 0;
 55     }
 56     dis[1] = 0;
 57     Q.push(std::make_pair(0, 1));
 58     for (; !Q.empty(); ) {
 59         int x = Q.top().second; Q.pop();
 60         if (flg[x]) continue;
 61         flg[x] = 1;
 62         for (int i = las[x]; i; i = pre[i]) {
 63             if (dis[to[i]] > dis[x] + wi[i]) {
 64                 dis[to[i]] = dis[x] + wi[i];
 65                 Q.push(std::make_pair(-dis[to[i]], to[i]));
 66             }
 67         }
 68     }
 69 }
 70
 71 int main() {
 72     freopen("return.in", "r", stdin);
 73     freopen("return.out", "w", stdout);
 74
 75     scanf("%d", &tc);
 76     for (; tc; --tc) {
 77         scanf("%d%d", &n, &m);
 78         Gragh_clear();
 79         for (int i = 1, x, y, a, l; i <= m; ++i) {
 80             //scanf("%d%d%d%d", &x, &y, &l, &a);
 81             Read(x); Read(y); Read(l); Read(a);
 82             Add(x, y, l); Add(y, x, l);
 83             e[i] = (Edge) { x, y, a };
 84         }
 85         Dij(); DSU::Init();
 86
 87         std::sort(e + 1, e + 1 + m);
 88         for (int i = 1; i <= m; ++i) {
 89             int x = DSU::Seek(e[i].u), y = DSU::Seek(e[i].v);
 90             if (x == y) continue;
 91             val[i + n] = e[i].a;
 92             mdi[i + n] = std::min(mdi[x], mdi[y]);
 93             DSU::Merge(i + n, x); DSU::Merge(i + n, y);
 94             gr[0][x] = gr[0][y] = i + n;
 95         }
 96
 97         for (int i = 1; i < LOG; ++i) {
 98             for (int j = 1; j <= n + m; ++j) {
 99                 if (gr[i - 1][j]) gr[i][j] = gr[i - 1][gr[i - 1][j]];
100             }
101         }
102
103         scanf("%d%d%d", &Qi, &k, &s);
104         for (int x, a, lans = 0; Qi; --Qi) {
105             //scanf("%d%d", &x, &a);
106             Read(x); Read(a);
107             x = (x + (LL) k * lans - 1) % n + 1;
108             a = (a + (LL) k * lans) % (s + 1);
109             for (int i = LOG - 1; ~i; --i) {
110                 if (gr[i][x] && val[gr[i][x]] > a) x = gr[i][x];
111             }
112             printf("%d\n", mdi[x]);
113             lans = mdi[x];
114         }
115     }
116
117     return 0;
118 }

View Code

$\bigodot$技巧&套路:

  • kruskal重构树的构建,最小生成树上最值问题的再探。

转载于:https://www.cnblogs.com/Dance-Of-Faith/p/9333015.html

【NOI 2018】归程(Kruskal重构树)相关推荐

  1. NOI 2018 归程 (Kruskal重构树)

    题目大意:太长了,略 Kruskal重构树,很神奇的一个算法吧 如果两个并查集被某种条件合并,那么这个条件作为一个新的节点连接两个并查集 那么在接下来的提问中,如果某个点合法,它的所有子节点也都合法, ...

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

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

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

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

  4. 洛谷 - P4768 [NOI2018]归程(Kruskal重构树+树上倍增+最短路)

    题目链接:点击查看 题目大意:去原网址看吧 题目分析:因为是在刷克鲁斯卡尔重构树的题目,所以稍微思考一下就能想出解法了,首先如果水位线固定了,剩下的边组成的最小生成树也是一定的,此时同一个连通块内的点 ...

  5. P4768 [NOI2018] 归程 Kruskal重构树 + 倍增 + 最短路

    传送门 文章目录 题意: 思路: 题意: 给你一个联通无向图,每条边有一个长度lll和海拔aaa,当海拔≤\le≤水位线的时候,说明这个道有积水.在起始点有一辆车,车可以走没有积水的路,下车后可以走有 ...

  6. [NOI2018] 归程(线段树维护并查集的可持久化/kruskal重构树,倍增+dijkstra最短路)

    [NOI2018] 归程 description solution1 code1 solution2 code description 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要 ...

  7. NOI2018 Day1 归程(Kruskal重构树)

    目录 NOI2018 Day1 return 题解 AC代码: NOI2018 Day1 return 题解 作为NOI Day1 的T1,这道题目还是比较清真的(虽然自己在同步赛的时候只打了70分的 ...

  8. NOI2018 D1T1 洛谷P4768 归程 (Kruskal重构树)

    题目传送门 实际上是一个最短路问题,但加上了海拔这个条件限制,要在海拔<水位线p中找最短路. 这里使用Kruskal重构树,将其按海拔建成小根堆,我们就可以在树中用倍增找出他不得不下车的点:树中 ...

  9. 【NOI2018】归程(kruskal重构树)

    这道题最后会化为这么一个问题:给一张图,每条边都有边权,多组询问,每次给出 u , k u,k u,k,问从 u u u 开始走,只走边权 ≤ k \leq k ≤k 的边,请维护 u u u 能走到 ...

最新文章

  1. 网页加速系列(七)、 网页加速之异步加载
  2. 计算机实验书,[计算机软件及应用]实验书.doc
  3. jsp页面定义的map
  4. c语言文件打开函数,C语言fopen函数中文件打开方式(参数值)
  5. 14-angular.isDefined
  6. php无限加载,php递归无限页面加载
  7. 重读GhostNet:使用轻量操作代替部分传统卷积层生成冗余特征以减少计算量
  8. 云速建站_华为云域名专场钜惠,助推中小企业云速建站
  9. redis数据结构、持久化、缓存淘汰策略
  10. 2018年计算机职称考试冲刺,2018年中级会计职称考试冲刺阶段学习计划
  11. C++ - 操作运算符
  12. 热传导方程有限差分法实现matlab,热传导方程有限差分法的MATLAB实现-史策
  13. Android WiFi Direct文件传输
  14. 打败特斯拉!深度起底「偶然亿万富翁」贾跃亭的法拉第野心
  15. 如何把微信删除的聊天记录恢复正常?你知道吗
  16. deepin外置键盘无法打开键盘背光灯的解决方法
  17. 常用网络结构:Alex,VGG,Resnet对比
  18. 5G网络时代助推社交电商,小蜜蜂社交电商的新生态新发展
  19. mysql中dateformat用法,MySQL date_format()函数
  20. (十二)命令模式详解(故事版) .

热门文章

  1. 利用微软平台生成报表,线性图,柱形图
  2. 集合框架中的接口及其实现类
  3. 代理对象我所理解的设计模式(C++实现)——代理模式(Proxy Pattern)
  4. Visual Studio 2005中编译调试新功能
  5. Android Studio maven-metadata.xml 卡着不动原因和解决方法
  6. SQL SERVER学习笔记(二)数据库管理
  7. zoj 3511 Cake Robbery(线段树)
  8. 如何为 Horizon View 配置 VMware VSAN?
  9. ffmpeg的新东东:AVFilter
  10. 日志文件在VS中输出为乱码问题