n<=100000个山,每个山有高度,从一个山到另一个山代价为高度差,有A和B两人一起开车,A每次选前进方向的次近山,B选最近,保证山高度不同且如果代价相同的山低的代价算小,每次旅行先A走,然后B,然后AB轮流开车,旅行如果下一次找不到目的地或者下一次到目的地时总代价超过了指定的X,他们就会停下。现完成两个任务:一,告诉X0,问从哪个点开始完成一次预算代价为X0的旅行会使A的路程比B的路程最小;二,m个询问,每次问从Si做预算Xi的旅行,A和B的行驶路程。

首先需要知道每个人后面的最近和次近山,双向链表、set、乱七八糟,随便搞。这里选双向链表,前面需要一个离散化:把每个数的排名连接起来,从1到n扫一次,每次用一个数的前驱、前驱的前驱、后继、后继的后继来比较出最近和次近,然后在双向链表中删除之。

由于A和B走一步的方式不一样,这样“跳”会比较复杂,不如把“跳”一步定义成A和B都走一次,这样可以处理一个ST表,表示从点i跳2^j步跳到哪里,以及期间A和B的行驶路程。用这个可以轻松算出所有的询问。

询问一:枚举从每个点开始跳,看最远能跳到哪,然后最后一步看A能不能再开一次。

询问二:同理。

倍增写挂了,开了个临时变量now来跳结果用i来跳。。。浪费了一晚上

 #include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<assert.h>
#include<algorithm>
//#include<queue>
//#include<iostream>
using namespace std; bool isdigit(char c) {return c>='' && c<='';}
int qread()
{
char c;int s=,t=;while (!isdigit(c=getchar())) (c=='-' && (t=-));
do s=s*+c-''; while (isdigit(c=getchar()));return s*t;
} int n;
#define maxn 100011
int pre[maxn],suc[maxn],zui[maxn],zuilu[maxn],ci[maxn],cilu[maxn],Rank[maxn],lisan[maxn],id[maxn];
#define LL long long
LL hei[maxn],f[maxn][],fa[maxn][],fb[maxn][];
void prepare()
{
for (int i=;i<=n+;i++) pre[i]=i-;
for (int i=;i<=n;i++) suc[i]=i+;
for (int i=;i<=n;i++) lisan[i]=hei[i];
sort(lisan+,lisan++n);
for (int i=;i<=n;i++) Rank[i]=lower_bound(lisan+,lisan++n,hei[i])-lisan,id[Rank[i]]=i;
for (int i=;i<=n;i++) assert(lisan[i]!=lisan[i-]);
// for (int i=1;i<=n;i++) cout<<Rank[i]<<' ';cout<<endl;
hei[]=-1e15;id[]=id[n+]=;
for (int i=;i<=n;i++)
{
LL x,y;
if (fabs((x=hei[id[suc[Rank[i]]]])-hei[i])<fabs((y=hei[id[pre[Rank[i]]]])-hei[i]))
{
zui[i]=id[suc[Rank[i]]];
zuilu[i]=fabs(x-hei[i]);
if (fabs((x=hei[id[suc[suc[Rank[i]]]]])-hei[i])<fabs(y-hei[i]))
{
ci[i]=id[suc[suc[Rank[i]]]];
cilu[i]=fabs(x-hei[i]);
}
else
{
ci[i]=id[pre[Rank[i]]];
cilu[i]=fabs(y-hei[i]);
}
}
else
{
zui[i]=id[pre[Rank[i]]];
zuilu[i]=fabs(y-hei[i]);
if (fabs(x-hei[i])<fabs((y=hei[id[pre[pre[Rank[i]]]]])-hei[i]))
{
ci[i]=id[suc[Rank[i]]];
cilu[i]=fabs(x-hei[i]);
}
else
{
ci[i]=id[pre[pre[Rank[i]]]];
cilu[i]=fabs(y-hei[i]);
}
}
pre[suc[Rank[i]]]=pre[Rank[i]];
suc[pre[Rank[i]]]=suc[Rank[i]];
}
for (int i=;i<=n;i++) f[i][]=zui[ci[i]],fa[i][]=cilu[i],fb[i][]=zuilu[ci[i]];
for (int j=;j<=;j++)
for (int i=,to=(n-(<<j)+);i<=to;i++)
{
f[i][j]=f[f[i][j-]][j-];
fa[i][j]=fa[i][j-]+fa[f[i][j-]][j-];
fb[i][j]=fb[i][j-]+fb[f[i][j-]][j-];
// cout<<i<<' '<<j-1<<' '<<f[i][j-1]<<' '<<fa[i][j-1]<<' '<<fb[i][j-1]<<endl;
}
// for(int i=1;i<=n;i++,puts("")) for(int j=0;j<=1;j++) printf("[%lld %lld %lld] ",f[i][j],fa[i][j],fb[i][j]);
} void work1()
{
int x0=qread();
bool flag=;
LL ansa=,ansb=;int ans=;
for (int i=;i<=n;i++)
{
LL tota=,totb=;int now=i;
for (int j=;j>=;j--) if (f[now][j])
if (fa[now][j]+fb[now][j]+tota+totb<=x0)
{
tota+=fa[now][j];
totb+=fb[now][j];
now=f[now][j];
// if (i==2) cout<<tota<<' '<<totb<<' '<<now<<endl;
}
if (ci[now] && cilu[now]+tota+totb<=x0) tota+=cilu[now],now=ci[now];
if (!flag) ansa=tota,ansb=totb,flag=,ans=i;
else if (totb)
{
if (!ansb) ansa=tota,ansb=totb,ans=i;
else if (1.0*ansa/ansb>1.0*tota/totb) ansa=tota,ansb=totb,ans=i;
else if (fabs(1.0*ansa/ansb-1.0*tota/totb)<1e- && hei[i]>hei[ans]) ans=i;
}
else if (!ansb && hei[i]>hei[ans]) ans=i;
// cout<<"now"<<now<<endl;
// cout<<tota<<' '<<totb<<endl;
}
printf("%d\n",ans);
} void work2()
{
int m=qread();int x,y;
while (m--)
{
x=qread(),y=qread();
LL tota=,totb=;
for (int j=;j>=;j--) if (f[x][j])
if (tota+fa[x][j]+totb+fb[x][j]<=y)
{
tota+=fa[x][j];
totb+=fb[x][j];
x=f[x][j];
}
if (ci[x] && cilu[x]+tota+totb<=y) tota+=cilu[x];
printf("%lld %lld\n",tota,totb);
}
} int main()
{
n=qread();
for (int i=;i<=n;i++) hei[i]=qread();
prepare();
work1();
work2();
// for (int i=1;i<=n;i++) cout<<zui[i]<<' '<<zuilu[i]<<' '<<ci[i]<<' '<<cilu[i]<<endl;
return ;
}

NOIP2012提高组D1T3 开车旅行的更多相关文章

  1. 【NOIP2012提高组】开车旅行 倍增

    题目分析 朴素的做法就是预处理下一个目的地,然后跑模拟,超时. 本题最重要的考点是倍增优化.设$fa[i][j]$表示a从i出发行驶$2^j$“次”后行驶的路程,$fb[i][j]$表示从i出发行驶$ ...

  2. 【noip 2012】提高组Day1T3.开车旅行

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

  3. NOIP2012提高组

    D1T1.Vigenère密码 模拟 #include<iostream> #include<cstdio> using namespace std; int main() { ...

  4. 刷题总结——疫情控制(NOIP2012提高组)

    题目: 题目背景 NOIP2012 提高组 DAY2 试题. 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都 ...

  5. GZOJ 1361. 国王游戏【NOIP2012提高组DAY1】

    国王游戏[NOIP2012提高组DAY1] Time Limit:1000MS Memory Limit:128000K Description 国王游戏(game.cpp/c/pas) [问题描述] ...

  6. [NOIP2012] 提高组 洛谷P1081 开车旅行

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

  7. [NOIP2012提高组]开车旅行

    题目:洛谷P1081.Vijos P1780.codevs1199. 题目大意:有n座海拔高度不相同的城市(编号1~n),两城市的距离就是两城市海拔之差.规定每次只能从编号小的城市走到编号大的城市. ...

  8. NOIP2012 提高组 Day 1

    期望得分:100+100+70=270 实际得分:100+50+70=220 T2 没有底 最后剩余时间来不及打高精.思路出现错误 T1 Vigenère 密码 题目描述 16 世纪法国外交家 Bla ...

  9. [NOIP2012] 提高组 洛谷P1084 疫情控制

    题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散 ...

随机推荐

  1. AJPFX关于java 知识点的集合

    1 .对象的初始化 (1 )非静态对象的初始化 在创建对象时,对象所在类的所有数据成员会首先进行初始化. 基本类型:int 型,初始化为0. 如果为对象:这些对象会按顺序初始化. ※在所有类成员初始化 ...

  2. 学习笔记 第十章 使用CSS美化表单

    第10章   使用CSS美化表单 [学习重点] 正确使用各种表单控件 熟悉HTML5新增的表单控件 掌握表单属性的设置 设计易用性表单页面 10.1  表单的基本结构 表单包含多个标签,由很多控件组成 ...

  3. Android开发中使用startActivityForResult()方法从Activity A跳转Activity B出现B退出时A也同时退出的解决办法

    最近一个 App 中用到了 startActivityForResult() 方法,使用的时候却出现了一些问题,比如我在 Activity A 中调用该方法向 Activity B 中跳转,如果 B  ...

  4. Java编程思想总结笔记Chapter 3

    本章需要总结的不多,但细节的东西需要注意,有些很容易遗忘. 第三章 目录: 3.1 更简单的打印语句 3.2 使用Java操作符 3.3 优先级 3.4 赋值 3.5 算数操作符 3.6 自动递增和递 ...

  5. ASP.NET Excel下载方法一览

    方法一 通过GridView(简评:方法比较简单,但是只适合生成格式简单的Excel,且无法保留VBA代码),页面无刷新 aspx.cs部分 using System; using System.Co ...

  6. ES6特性的两点分析

    块级作用域声明let.constES6中const 和let的功能,转换为ES5之后,我们会发现实质就是在块级作用改变一下变量名,使之与外层不同.ES6转换前: let a1 = 1; let a2 ...

  7. 对称加密DES加密

    DES加密: des是对称加密,加密和解密需要相同的秘钥,它的密码最长56位,必须是8的倍数,秘钥越长,越安全. package com.trm.util.encrypt; import java.s ...

  8. MySQL索引的用处

    MySQL索引在MySQL数据库中,可以有效提高查询的效率,尤其是查询数据量非常大时,效果更为明显,往往能使查询速度加快成千上万倍. MySQL索引是很重要的概念,应用的范围非常广.那么,MySQL索 ...

  9. Java 斜杠 与 反斜杠

    除号 /(数字键盘的斜杠)网址 /(数字键盘的斜杠)文件地址 \转义 \正则表达式 \

  10. CAD参数绘制实心圆弧填充(网页版)

    js中实现代码说明: function DrawPathToHatch1() { //把路径的开始位置移动指定的点 //参数一为点的X坐标 ,参数二为点的Y坐标,参数三为该点处开始宽度,对Polyli ...