题面

​ 这个题目还是值得思考的.

​ 看到这个题目, 大家应该都想到了这样一个思路, 就是把每个点能够达到的最近的和次近的点都预处理出来, 然后跑就可以了, 现在问题就是难在这个预处理上面, 我们应该如何做呢? 观察到, 近的概念是两点之间的海拔距离最小, 所以我们可以将海拔距离从后往前(毕竟你只能往你后面的地方走嘛...), 扔进一个可以维护大小关系的数据结构中, 不妨设当前点海拔进入这个数据结构后位置为\(k\), 那么我们只需要比较位置为\(k - 1\), \(k - 2\), \(k + 1\), \(k + 2\)的四个数就可以了, 大家可以自己在纸上分类讨论一下, 这里就不做过多的阐述了. 现在我们只需要知道这个数据结构就可以了, 大家想一想, 有什么数据结构可以快速的找到某个数排序后的位置呢? 平衡树, 查找和插入的复杂度都为\(\log_ {2}{n}\)了, 这样我们就可以快速寻找了, 当然, 因为有重复结构, 所以用STL中的\(multiset\)是比较好的一种办法(其实是我不会双向链表), 这样我们就将比较难想的预处理部分弄出来了.

​ 当然, 想完了预处理后我们就可以想接下来怎么走了. 比较快速的方法是倍增, \(f[i][j][opt]\)表示当前位置为\(i\), 已经走了\(2 ^j\)天, \(opt\)为1时代表从\(i\)位置开始走, 第一个走的是B所走到的位置, 那么\(opt\)是\(0\)时就是A了. \(disa[i][j][opt]\)代表在第\(i\)位出发, 走了\(2 ^ j\)天, \(opt\)为1代表从\(i\)开始走, B先出发, 在这段时间中A走的距离, opt为\(0\)自己推一下吧, 实在是不想打了, \(disb[i][j][opt]\)也自己照着看一下吧. 我们在预处理出每个点的最近点和次近点后, 就可以处理出来了.

​ 至此, 预处理完毕, 剩下的代码中会说到的.

具体代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <set>
#define N 100005
using namespace std;int n, x0, m, f[N][22][2], disa[N][22][2], disb[N][22][2], bin;
struct node
{int id, h;bool operator < (const node &p) const { return h < p.h; }
} ht[N]; multiset<node> s;
multiset<node> :: iterator it; inline int read()
{int x = 0, w = 1;char c = getchar();while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }return x * w;
}inline void get_ans(int S, int &dist_a, int &dist_b, int limit)
{int now = S;for(int i = 20; i >= 0; i--)if(f[now][i][0] && disa[now][i][0] + disb[now][i][0] + dist_a + dist_b <= limit)//倍增跑, 注意当没有能够跑的地方或者超过了给定的值的话就需要continue{dist_a += disa[now][i][0];dist_b += disb[now][i][0];now = f[now][i][0]; }
}inline long long abs(long long x) { return x < 0 ? -x : x; }inline void init()
{for(int i = n; i >= 1; i--){int Ato, Bto; node nxt, pre;s.insert(ht[i]);//先插入当前海拔, 方便找it = s.lower_bound(ht[i]);//找到当前海拔在序列中的位置it++; nxt = (*it); it--; it--; pre = (*it);it++;if(abs(nxt.h - ht[i].h) < abs(pre.h - ht[i].h)){it++, it++;Bto = nxt.id;if(abs(pre.h - ht[i].h) > abs((*it).h - ht[i].h)) Ato = (*it).id; else Ato = pre.id;}else{//同上it--, it--;Bto = pre.id;if(abs(nxt.h - ht[i].h) >= abs((*it).h - ht[i].h)) Ato = (*it).id;else Ato = nxt.id; }//注意, 这里由于前后海拔差相同的话取海拔较低的, 所以有的地方有等于号, 有的地方没有, 希望大家能够自己好好去想一下为什么, 有问题可以私信我(反正我不会回答的(手动删除)).f[i][0][0] = Ato; f[i][0][1] = Bto;disa[i][0][0] = abs(ht[Ato].h - ht[i].h); disb[i][0][0] = 0;disb[i][0][1] = abs(ht[Bto].h - ht[i].h); disa[i][0][1] = 0;}for(int i = 1; i <= n; i++)//由于上面并没有讨论到A, B都走过了的情况, 只讨论了A和B单独走的情况, 故在这里要处理一下.{f[i][1][0] = f[f[i][0][0]][0][1];f[i][1][1] = f[f[i][0][1]][0][0];disa[i][1][1] = abs(ht[f[i][1][1]].h - ht[f[i][0][1]].h); disb[i][1][0] = abs(ht[f[i][1][0]].h - ht[f[i][0][0]].h);disa[i][1][0] = disa[i][0][0]; disb[i][1][1] = disb[i][0][1]; //类似于倍增LCA中的预处理}for(int j = 2; j <= 20; j++)for(int i = 1; i <= n; i++){f[i][j][0] = f[f[i][j - 1][0]][j - 1][0];f[i][j][1] = f[f[i][j - 1][1]][j - 1][1];disa[i][j][0] = disa[i][j - 1][0] + disa[f[i][j - 1][0]][j - 1][0];disb[i][j][0] = disb[i][j - 1][0] + disb[f[i][j - 1][0]][j - 1][0];disa[i][j][1] = disa[i][j - 1][1] + disa[f[i][j - 1][1]][j - 1][0];disb[i][j][1] = disb[i][j - 1][1] + disb[f[i][j - 1][1]][j - 1][0]; //仔细思考一下, 应该不难}
}int main()
{n = read();for(int i = 1; i <= n; i++) { ht[i].h = read(); ht[i].id = i; }ht[0].h = 2e9 + 7; ht[n + 1].h = -(2e9 + 7); ht[0].id = 0; ht[n + 1].id = n + 1;//我取2147483647爆掉了, 调了整整一上午, 所以取极值的时候需要注意一下s.insert(ht[0]); s.insert(ht[0]); s.insert(ht[n + 1]); s.insert(ht[n + 1]);//插入两个极小值和极大值代表我们在找到位置k的时候, 他前后总会至少有两个点, 免去了分类讨论的冗杂init(); //预处理x0 = read(); m = read();int id = 0;double ans = 1e16;for(int i = 1; i <= n; i++)//枚举每一个点为起点时的比例{int dist_a = 0, dist_b = 0;get_ans(i, dist_a, dist_b, x0);if(dist_b == 0){if(ans > 1e14) { ans = 1e14; id = i; }else if(ans == 1e14 && ht[i].h > ht[id].h) id = i; }else{double res = (double) dist_a / dist_b;if(res < ans) { ans = res; id = i; }else if(res == ans && ht[i].h > ht[id].h) id = i; }}printf("%d\n", id);for(int i = 1; i <= m; i++){bin = read(); x0 = read();int dist_a = 0, dist_b = 0;get_ans(bin, dist_a, dist_b, x0);printf("%d %d\n", dist_a, dist_b); }return 0;
}

转载于:https://www.cnblogs.com/ztlztl/p/10447356.html

[luogu1081] 开车旅行相关推荐

  1. NOIP2012 开车旅行

    开车旅行 (drive.cpp/c/pas) [问题描述] 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度 ...

  2. NOIP2012提高组 开车旅行 解题报告

    开车旅行 题目描述 样例输入 样例输出 70分算法 暴力预处理出对于每一个点他右边最近.次近的点的编号,对于每一个询问,暴力模拟开车过程即可. 100算法 和上面一样我们得预处理出每一个点最近.次近的 ...

  3. 刷题记录(NC16562 开车旅行)(树上倍增)

    NC16562 开车旅行 题目链接 关键点: 1.预处理:将所有点到达另一个点的最短和次短距离先求出 方法:利用set,从最后一个城市开始插入,每次插入到set中,查看左右是否存在有城市(即set是按 ...

  4. NOIP2012开车旅行 【倍增】

    题目 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i 和城 ...

  5. 【NOIP2012提高组】开车旅行

    Description 现在有n个城市,每个城市有它的高度 Hi H_i,保证每个 Hi H_i互不相同.我们定义两个城市之间的距离 disi,j=|Hi−Hj| dis_{i,j}=|H_i-H_j ...

  6. NOIP2012DAY1T3【开车旅行】

    Description 小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市i 的海拔高度为Hi,城市i 和城市 ...

  7. 题解 P1081 【开车旅行】

    小 A \text{A} A 和小 B \text{B} B 决定利用假期外出旅行,他们将想去的城市从 $1 $ 到 n n n 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互 ...

  8. NOIP 2012 开车旅行

    题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...

  9. 【NOIP2012】开车旅行

    题目描述: 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...

  10. NOIP2012 开车旅行 (倍增)

    题意:一行N个城市,有各自不同的海拔,定义两个城市之间的距离为海拔之差的绝对值,小a和小b轮流开车,开车方向从左往右,小a总是开到第二近的城市,小b开到最近的城市(如有两个城市和当前城市海拔之差相等, ...

最新文章

  1. Camel In Action 读书笔记 (1)
  2. 利用TinyXML读取VOC2012数据集的XML标注文件裁剪出所有人体目标保存为文件
  3. ACM入门之【离散化】
  4. idea 运行jmeter源码_学会BeanShell,才敢说自己懂Jmeter
  5. Cloud Toolkit 部署应用到阿里云轻量应用服务器
  6. 小熊的人生回忆(三)
  7. Kotlin入门(21)活动页面的跳转处理
  8. Linux下安装composer报错 The openssl extension is missing / The zlib extension is not loaded等等
  9. 美国最受欢迎的量化交易模型有哪些吗?
  10. UEditor的使用
  11. Mybatis——持久层框架
  12. wps垂直居中快捷键_水平与垂直居中怎么设置 在wps中的水平垂直居中在哪
  13. php laravel 开发工具,Laravel 文档工具
  14. 三、经典比特与量子比特
  15. 微信公众上传头像和分享
  16. NOT NULL 和 DEFAULT 的区别
  17. POJ 1625 Censored!
  18. MThings连接移动OneNet物联网平台
  19. 纯纯写作开发者知识星球推荐
  20. C++中的枚举(enum)

热门文章

  1. 设计模式_07_单例模式
  2. 创业型 APP 如何筛选合适的推送平台
  3. 安装金蝶K3 提示:“安装包配置文件(setup.lst)文件不存在”
  4. SpringBoot多数据源切换详解,以及开启事务后数据源切换失败处理
  5. 批处理(bat)choice命令详解
  6. Java基础HashMap---面试题【二】
  7. 44. Factor parameter-independent code out of templates.
  8. 3西格玛计算公式_西格玛和西格玛水平
  9. java 函数委托_Java反射实现.NET委托
  10. gatewayworker配置php,tp5整合GatewayWorker