今年D1T1,平心而论,如果能想到kruskal重构树还是很简单的。

......苟屁啊!虽然跟其他的比是简单些,但是思维难度中上,代码难度中上,怎么看都很符合NOI T1啊。

本题还有可持久化并查集的做法,以高度为版本。我没有打......

言归正传,来看题。

给你一个无向图,每条边有高度和长度。每次询问,从点s出发,只能经过高度大于h的边所能到达的点中,距1号点最近的点的距离。强制在线。

n<=200000,m<=400000,q<=400000

首先,离线有65分,十分可观。我们把边和询问都按照高度排序。然后依次加入,并查集维护连通块内dis最小值。

克鲁斯卡尔重构树解法:

首先讲什么是克鲁斯卡尔重构树:说起来也蛮简单,就是你把边排序,加边的时候如果连通就不加,否则新建节点代表这个连通块,边的两端所在连通块的代表节点作为这个新节点的两个子节点。

这样你要查询高度h时dis min,只需维护一个节点所代表连通块内dis最小值即可。每次向上跳,可以发现一条链上的dis min单调不增。然后就倍增了,类似lca。

啊我到底在口胡什么。

 #include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue> const int N = , INF = 0x7f7f7f7f; struct Edge_1 {
int v, len, nex;
}edge_1[N << ]; int top_1; // for dijkstra struct POI {
int id, dis;
inline bool operator <(const POI &d) const {
return dis > d.dis;
}
POI(int a, int b) {
id = a;
dis = b;
}
}; // for dijkstra struct Edge_2 {
int u, v, h;
inline bool operator <(const Edge_2 &d) const {
return h > d.h;
}
}edge_2[N << ]; int top_2; // for sort kruskal struct UFS {
int fa[N * ];
inline void clear() {
for(int i = ; i < N * ; i++) {
fa[i] = i;
}
return;
}
UFS() {
clear();
}
int find(int x) {
if(fa[x] == x) {
return x;
}
return fa[x] = find(fa[x]);
}
inline void merge(int x, int y) { // x <- y
fa[find(y)] = find(x);
return;
}
}ufs; int e[N], dis[N * ]; // for dijkstra
int fa[N * ][], tot, h[N * ]; // for kruskal inline void add_1(int x, int y, int z) {
top_1++;
edge_1[top_1].v = y;
edge_1[top_1].len = z;
edge_1[top_1].nex = e[x];
e[x] = top_1;
return;
} inline void add_2(int x, int y, int z) {
top_2++;
edge_2[top_2].u = x;
edge_2[top_2].v = y;
edge_2[top_2].h = z;
return;
} inline void clear() {
top_1 = ;
top_2 = ;
memset(e, , sizeof(e));
ufs.clear();
return;
} inline void dijkstra() {
std::priority_queue<POI> Q;
memset(dis, 0x3f, sizeof(dis));
dis[] = ;
Q.push(POI(, )); // POI(id, dis)
while(!Q.empty()) {
while(!Q.empty() && dis[Q.top().id] != Q.top().dis) {
Q.pop();
}
if(Q.empty()) {
break;
}
int x = Q.top().id;
Q.pop();
for(int i = e[x]; i; i = edge_1[i].nex) {
int y = edge_1[i].v;
if(dis[y] > dis[x] + edge_1[i].len) {
dis[y] = dis[x] + edge_1[i].len;
Q.push(POI(y, dis[y]));
}
}
}
return;
} inline void add(int p) {
int x = ufs.find(edge_2[p].u);
int y = ufs.find(edge_2[p].v);
if(x == y) {
return;
}
++tot;
fa[x][] = tot;
fa[y][] = tot;
ufs.merge(tot, x);
ufs.merge(tot, y);
h[tot] = edge_2[p].h;
dis[tot] = std::min(dis[x], dis[y]);
return;
} inline int solve(int x, int high) {
int t = ;
while(t >= ) {
if(h[fa[x][t]] > high) {
x = fa[x][t];
}
t--;
}
return dis[x];
} int main() {
int T;
scanf("%d", &T);
while(T--) {
int n, m;
scanf("%d%d", &n, &m);
tot = n;
h[] = -;
for(int i = , x, y, z, w; i <= m; i++) {
scanf("%d%d%d%d", &x, &y, &z, &w);
add_1(x, y, z);
add_1(y, x, z);
add_2(x, y, w);
} // prework
dijkstra();
std::sort(edge_2 + , edge_2 + m + );
for(int i = ; i <= m; i++) {
add(i);
}
for(int i = ; i <= ; i++) {
for(int x = ; x <= tot; x++) {
fa[x][i] = fa[fa[x][i - ]][i - ];
}
} int q, k, s, op, high, la = ;
scanf("%d%d%d", &q, &k, &s);
while(q--) {
scanf("%d%d", &op, &high);
op = (op + k * la - ) % n + ;
high = (high + k * la) % (s + );
la = solve(op, high);
printf("%d\n", la);
}
clear();
}
return ;
}

AC代码

170行代码还行。

[NOI2018]归程的更多相关文章

  1. [NOI2018]归程 kruskal重构树

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

  2. [洛谷P4768] [NOI2018]归程 (kruskal重构树模板讲解)

    洛谷题目链接:[NOI2018]归程 因为题面复制过来有点炸格式,所以要看题目就点一下链接吧\(qwq\) 题意: 在一张无向图上,每一条边都有一个长度和海拔高度,小\(Y\)的家在\(1\)节点,并 ...

  3. NOI2018 D1T1 [NOI2018]归程 解题报告

    P4768 [NOI2018]归程 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 \(n\) 个节点.\(m\) 条边的无向连通图(节点的编号从 \ ...

  4. BZOJ_5415_[Noi2018]归程_kruscal重构树+倍增+最短路

    BZOJ_5415_[Noi2018]归程_kruscal重构树+倍增 Description www.lydsy.com/JudgeOnline/upload/noi2018day1.pdf 好久不 ...

  5. 题解 NOI2018 归程

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

  6. [NOI2018]归程(kruscal重构树)

    [NOI2018]归程 题面太长辣,戳这里 模拟赛上写了一个spfa (关于spfa,它已经死了),然后一个st表水完暴力跑路.考后说是Kruscal重构树或者可持久化并查集???这都是些什么东西.不 ...

  7. [luogu4768] [NOI2018] 归程 (Dijkstra+Kruskal重构树)

    [luogu4768] [NOI2018] 归程 (Dijkstra+Kruskal重构树) 题面 题面较长,这里就不贴了 分析 看到不能经过有积水的边,即不能经过边权小于一定值的边,我们想到了kru ...

  8. Luogu P4768 [NOI2018]归程(Dijkstra+Kruskal重构树)

    P4768 [NOI2018]归程 题面 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 \(n\) 个节点. \(m\) 条边的无向连通图(节点的编 ...

  9. P4768 [NOI2018]归程(kruskal 重构树)

    洛谷P4768 [NOI2018]归程 LOJ#2718.「NOI2018」归程 用到 kruskal 重构树,所以先说这是个啥 显然,这和 kruskal 算法有关系 (废话 这个重构树是一个有点权 ...

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

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

随机推荐

  1. CSS3 background-size属性兼容

    background-size是CSS3新增的属性,但是IE8以下还是不支持 background-size:contain; // 缩小图片来适应元素的尺寸(保持像素的长宽比):background ...

  2. laravel5.3安装redis扩展包

    1,编辑 laravel 根目录下的 composer.json 文件: "require": { "php": ">=5.6.4", ...

  3. DAY07、字符编码和文件操作

    一.字符编码 1.什么是字符编码? 人类能识别的是字符等高级标识符,电脑只能识别0,1组成的标识符,要完成人与机器之间的信息交流,              一定需要一个媒介,进行两种标识符的转化(两 ...

  4. python数据结构与算法第十二天【快速排序】

    1. 原理如图所示: 2.代码实现 def quick_sort(alist, start, end): """快速排序""" # 递归的退 ...

  5. delphi中退出是弹出让你确定的几种确定对话框怎么写?

    procedure TForm2.btn1Click(Sender: TObject); begin if MessageBox(Handle, '你确定要退出系统吗?', '信息提示', MB_OK ...

  6. 一、Dev

    一.获取选中的表格 // MessageBox.Show(gridview_Parent.GetFocusedDataRow()["series"].ToString());//获 ...

  7. 解决Safari页面缓存的问题

    在开发一个移动应用的过程中,遇到问题:在订单确认页,用户点击 收货地址链接,跳转到地址选择页面,咋选一个地址,跳转回订单确认页,发现收货地址没有改变,还是最开始的地址. 用Android手机发现地址有 ...

  8. ES 6 系列 - 对于常用对象的拓展 api

    本篇中学习并记录可能会比较常用的 api ,详细请自行查找相关资料. 一.字符串的拓展 es 6 加强了对于 Unicode 的支持.javascript 允许采用 \uxxxxx 的方式表示一个字符 ...

  9. Spring Boot 构建电商基础秒杀项目 (六) 用户登陆

    SpringBoot构建电商基础秒杀项目 学习笔记 userDOMapper.xml 添加 <select id="selectByTelphone" resultMap=& ...

  10. CountDownLatch(三)

    CountDownLatch简介 (1)用于解决什么问题? 在并发编程的场景中,最常见的一个case是某个任务的执行,需要等到多个线程都执行完毕之后才可以进行,CountDownLatch可以很好解决 ...