题目连接

题意

题目已经说的hin明确了。

题解

我们要求出从每个点出发,小A要走的城市和小B要走的城市。

我们把iii以后的所有点的海拔加入到set" role="presentation" style="position: relative;">setsetset,然后拿H[i]H[i]H[i]到set里面去lower_bound,找到比H[i]大的两个地点和比H[i]小的两个地点,并把这四个地点与H[i]的差值加入到新的排序数组中,排个序,找到差值最小的两个点,分别就是小B要选的目的地和小A要选的目的地。
在这里注意一点,就是当差值最小的两个值相等的时候,小B走的是海拔较低的那个点,涉及到第二关键字的问题,我们可以用一个比较省事的方法,那就是给海拔低的点计算差值时候乘以99999999,海拔较高的点计算差值时候乘以100000000。

定义需要的状态

nxt1[i]nxt1[i]nxt1[i]代表从iii出发,小B的目的地。
nxt2[i]" role="presentation" style="position: relative;">nxt2[i]nxt2[i]nxt2[i]代表从iii出发,小A的目的地。
nxt3[i][j]" role="presentation" style="position: relative;">nxt3[i][j]nxt3[i][j]nxt3[i][j]代表从iii出发,(小A走完、小B走完)2j" role="presentation" style="position: relative;">2j2j2^{j}轮,所达到的目的
地。

DP1[i][j]DP1[i][j]DP1[i][j]代表从i出发,(小A走完、小B走完)2j2j2^{j}轮,小B所经过的距离。

DP2[i][j]DP2[i][j]DP2[i][j]代表从i出发,(小A走完、小B走完)2j2j2^{j}轮,小A所经过的距离。

nxt3,DP1,DP2可以用类似于处理ST表的方法求出来。

函数解释

一轮代表小A走一次+小B走一次。
getdp(int &S,int len,ll &ans1,ll &ans2)
从S出发,走len轮,返回ans1为小B走过的路程,返回ans2为小A走过的路程,并且把S改变为len轮以后到达的点。
getmx(int S,ll X)
从S出发,总路程不能超过X,返回最大能走几轮。

回答询问

给出SiSiSi和XiXiXi,用二分的方法求出从Si出发小A和小B最长能走的长度。


代码

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pll;
set<pll>::iterator it;
const int maxn = 500007;
int nxt1[maxn],nxt2[maxn],nxt3[maxn][30];
int N,LOG,X0,M;
ll H[maxn],H2[maxn],H1[maxn],DP2[maxn][30],DP1[maxn][30];
pll tmpsort[7];
void getdp(int &S,int len,ll &ans1,ll &ans2){int cnt = 0;while(len){if(len & 1){ans1 += DP1[S][cnt];ans2 += DP2[S][cnt];S = nxt3[S][cnt];}len >>= 1;cnt++;if(!S) break;}return ;
}
int getmx(int S,ll X){int l = 0,mid,r = N+1;while(r - l > 1){mid = (l+r)/2;int nS = S;ll ans1 = 0,ans2 = 0;getdp(nS,mid,ans1,ans2);if(ans1+ans2 > X || !nS)r = mid;else l = mid;}return l;
}
int main(){set<pll> st;cin>>N;int tmp = 1;while(tmp <= N/3)LOG++,tmp <<= 1;for(int i = 1;i <= N;++i){scanf("%lld",&H[i]);st.insert(make_pair(H[i],i));}for(int i = 1;i < N;++i){int ct = 0;st.erase(make_pair(H[i],i));it = st.lower_bound(make_pair(H[i],i));if(it != st.end()){tmpsort[ct++] = make_pair(abs(H[i]-(*it).first)*100000000,(*it).second);    ++it;}if(it != st.end()){tmpsort[ct++] = make_pair(abs(H[i]-(*it).first)*100000000,(*it).second);    }  it = st.lower_bound(make_pair(H[i],i));if(it != st.begin()) {--it;tmpsort[ct++] = make_pair(abs(H[i]-(*it).first)*99999999,(*it).second);    if(it != st.begin()){--it;tmpsort[ct++] = make_pair(abs(H[i]-(*it).first)*99999999,(*it).second); }}sort(tmpsort,tmpsort+ct);if(ct > 0)nxt1[i] = tmpsort[0].second;if(ct > 1)nxt2[i] = tmpsort[1].second;}for(int i = 1;i < N;++i)nxt3[i][0] = nxt1[nxt2[i]];for(int i =1;i <= N;++i){if(nxt1[i])H1[i] = abs(H[nxt1[i]] - H[i]);if(nxt2[i]){H2[i] = abs(H[nxt2[i]] - H[i]);DP2[i][0] = abs(H[nxt2[i]] - H[i]);}if(nxt1[nxt2[i]])DP1[i][0] = abs(H[nxt1[nxt2[i]]] - H[nxt2[i]]);}for(int j = 1;j <= LOG;++j){for(int i = 1;i <= N;++i){nxt3[i][j] = nxt3[nxt3[i][j-1]][j-1];DP1[i][j] = DP1[i][j-1] + DP1[nxt3[i][j-1]][j-1];DP2[i][j] = DP2[i][j-1] + DP2[nxt3[i][j-1]][j-1];}}int mf1 = 0,mf2 = 1,mh = 0;int ans1 = 1;cin>>X0>>M;for(int i = 1;i <= N;++i){ll f1 = 0,f2 = 0;int nS = i;int mxl = getmx(i,X0);getdp(nS,mxl,f1,f2);if(nxt2[nS] && H2[nS]+f1+f2 <= X0)f2 += H2[nS];if(!f2) continue;if(mf1*f2 < f1*mf2){mf1 = f1;mf2 = f2;ans1 = i;mh = H[i];}else if(mf1*f2 == mf2*f1 && H[i] > mh){mf1 = f1;mf2 = f2;ans1 = i;mh = H[i];}}cout<<ans1<<endl;for(int i = 0;i < M;++i){int Si,nSi;ll Xi;scanf("%d %lld",&Si,&Xi);nSi = Si;int mxl = getmx(Si,Xi);ll f1 = 0,f2 = 0;getdp(nSi,mxl,f1,f2);if(nxt2[nSi] && H2[nSi]+f1+f2 <= Xi)f2 += H2[nSi];printf("%lld %lld\n",f2,f1);}return 0;
}

P1081 开车旅行 倍增 洛谷相关推荐

  1. 2018.11.04 洛谷P1081 开车旅行(倍增)

    传送门 思路简单码量超凡? 感觉看完题大家应该都知道是倍增sbsbsb题了吧. 首先预处理出从每个点出发如果是AAA走到哪个点,如果是BBB走到哪个点. 然后利用刚刚预处理出的信息再预处理从每个点出发 ...

  2. NOIP2012 开车旅行 (倍增)

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

  3. poi word转html 根号,#根号分治,树上倍增#洛谷 3591 [POI2015]ODW

    分析 考虑直接用倍增跳会TLE,设\(f[x][i]\)表示以\(x\)为起点每次跳\(i\)步的点权和, 这可以预处理出来,综合一下两种做法,当\(i>\sqrt{n}\)时直接上倍增,否则预 ...

  4. P1081 [NOIP2012 提高组] 开车旅行(倍增)(动态规划)

    洛谷传送门 文章目录 题目描述 解析 代码 题目描述 解析 利用倍增,设计dp慢慢敲即可... 注意距离累加在一起会爆int,需要ll 特判条件非常之复杂... 心力交瘁,就酱了 代码 #includ ...

  5. DP【洛谷P2134】 百日旅行

    [洛谷P2134] 百日旅行 题目背景 重要的不是去哪里,而是和你在一起.--小红 对小明和小红来说,2014年7月29日是一个美好的日子.这一天是他们相识100天的纪念日. (小明:小红,感谢你2场 ...

  6. 洛谷 P1027 Car的旅行路线

    洛谷 P1027 Car的旅行路线 题目描述 又到暑假了,住在城市 A 的 Car 想和朋友一起去城市 B 旅游.她知道每个城市都有 4 个飞机场,分别位于一个矩形的 4 个顶点上,同一个城市中 2  ...

  7. 倍增:喷泉 深度解析(洛谷P7167)

    洛谷传送门 解析 什么破题 数据范围来看很明显最多到nlogn 首先,对于样例进行一下分析: 我们可以把它转化为一棵树: 每一个根都有对应的权,给你一个结点和加权和,问能爬到哪里 既然是树,自然要找爸 ...

  8. 信息学奥赛一本通 1343:【例4-2】牛的旅行 | 洛谷 P1522 [USACO2.4] 牛的旅行 Cow Tours

    [题目链接] ybt 1343:[例4-2]牛的旅行 洛谷 P1522 [USACO2.4] 牛的旅行 Cow Tours [题目考点] 1. 图论 最短路径 Floyd算法 Floyd算法时间复杂度 ...

  9. 【洛谷】P1137旅行计划

    [洛谷]P1137旅行计划 题目描述 小明要去一个国家旅游.这个国家有N个城市,编号为1至N,并且有M条道路连接着,小明准备从其中一个城市出发,并只往东走到城市i停止. 所以他就需要选择最先到达的城市 ...

最新文章

  1. 基于迁移学习的反欺诈方法研究
  2. cocos2d-x之逐帧动画
  3. [渝粤教育] 中国地质大学 自动控制原理 复习题
  4. 商品WEB开发的商品定单与存储过程的应用
  5. STM32 寄存器库和固件库
  6. scala json处理入门
  7. 漫画 | 硬核技术预测你有没有女朋友
  8. bcoma 应用程序发生错误_Golang 错误和异常处理(含生产环境下的解决方案)
  9. SSH: 关于remote主机上操作系统变更后SSH连接问题
  10. 换IP软件能保证我们的网络安全吗
  11. 【雕虫小技第8篇】scratch编程技巧之源码中的图片素材资源导出!
  12. VB写的随机点名器代码
  13. 三维计算机学校,什么是三维虚拟校园系统?
  14. 阿里云OCR图片文字识别使用教程
  15. SEO基本概念之死链接
  16. python读txt写入excel_python实现读Excel写入.txt的方法
  17. 修改Hosts文件解决文件访问问题
  18. python小说文本挖掘_Python小说文本挖掘正则表达式分析案例
  19. 实在智能“数字员工”发布,谈AI+RPA发展趋势,发布SaaS平台,并开源可供开发者下载打造小型机器人
  20. 关于bas的几例配置

热门文章

  1. circle后面是什么意思 python_Ape circle Python操作-第2-01章-列表操作,小猿圈,作业
  2. leetcode剑指 Offer 29. 顺时针打印矩阵
  3. [mybatis]Mapper XML Files_获取自增主键的值
  4. C++泛型编程实现哈希表(开散列法)
  5. 数据结构与算法-- 二叉树中和为某一值的路径
  6. Educational Codeforces Round 73 (Rated for Div. 2) F. Choose a Square 线段树 + 二维转一维
  7. newcode Islands 思维
  8. 【CF1338C】Perfect Triples【位运算】【构造】
  9. 【NOI2012】骑行川藏【拉格朗日乘数法】【二分套二分】
  10. CF868F Yet Another Minimization Problem