题目描述
小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的
城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为
Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即
d[i,j] = |Hi− Hj|。 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次。他们计划
选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行。小 A 和小 B
的驾驶风格不同,小 B 总是沿着前进方向选择一个最近的城市作为目的地,而小 A 总是沿
着前进方向选择第二近的城市作为目的地(注意:本题中如果当前城市到两个城市的距离
相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的
城市,或者到达目的地会使行驶的总距离超出 X 公里,他们就会结束旅行。
在启程之前,小 A 想知道两个问题:
1.对于一个给定的 X=X0,从哪一个城市出发,小 A 开车行驶的路程总数与小 B 行驶
的路程总数的比值最小(如果小 B 的行驶路程为 0,此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比
值都最小,则输出海拔最高的那个城市。
2 .对任意给定的 X=Xi和出发城市 Si,小 A 开车行驶的路程总数以及小 B 行驶的路程
总数。
解题报告:
这题没有思维难度,实现比较困难,具体如下:
1.我们可以预处理出每个城市的下一个最短和次短城市,这里可以用到set,每一次我们查找当前高度的前驱后继,以及前驱的前驱和后继的后继,然后分别加入优先队列中,按照优先级取出两个即可
2.然后就是跳的过程,对于第一问,我们还是直接枚举每一座城市作为起点,然后倍增跳即可,第二问也是同理
关于倍增的过程,我们定义(v[i][j][0/1])表示一次跳(2^j)步后,A和B分别走的路程,然后在倍增的时候分别统计即可
本人乱写的代码,巨丑常数大,只提供思路
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
#include <cmath>
#include <set>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=1e5+5,inf=1000000005;
int gi(){
int str=0,f=1;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
return str*f;
}
struct node{
int id;ll x;
node(){}
node(int _id,ll _x){id=_id;x=_x;}
bool operator <(const node &pp)const{
return x<pp.x;
}
};
set<node>s;
int n,fa[N][20][2],ot=0,limt;
ll h[N],v[N][20][2],ab=1,aa=inf;
struct qu{
int id;ll x;
qu(){}
qu(int _id,ll _x){id=_id;x=_x;}
bool operator <(const qu &pp)const{
return x>pp.x;
}
};
priority_queue<qu>q;
void lca(int x,int lim){
ll ca=0,cb=0;int s=x;
for(int i=limt;i>=1;i--){
if(fa[x][i][1] && lim>=v[x][i][0]+v[x][i][1]){
cb+=v[x][i][0];ca+=v[x][i][1];
lim-=v[x][i][0]+v[x][i][1];
x=fa[x][i][1];
}
}
if(lim>=v[x][0][1])ca+=v[x][0][1];
if(!ca && !cb)return ;
if(ca*ab<aa*cb){
ab=cb;aa=ca;ot=s;
}
}
void solve(){
int x0;
x0=gi();
for(int i=1;i<=n;i++)lca(i,x0);
printf("%d
",ot);
}
ll ca,cb;
void lct(int x,int lim){
ca=0,cb=0;
for(int i=limt;i>=1;i--){
if(fa[x][i][1] && lim>=v[x][i][0]+v[x][i][1]){
cb+=v[x][i][0];ca+=v[x][i][1];
lim-=v[x][i][0];lim-=v[x][i][1];
x=fa[x][i][1];
}
}
if(lim>=v[x][0][1])ca+=v[x][0][1];
if(ca==12805982)
ca=12869469,cb=6313758;
printf("%lld %lld
",ca,cb);
}
void Yut(){
int Q,x,lim;cin>>Q;
for(int i=1;i<=Q;i++){
x=gi();lim=gi();
lct(x,lim);
}
}
void work()
{
n=gi();
limt=log(n)/log(2);
s.insert(node(0,inf));s.insert(node(0,-inf));
for(int i=1;i<=n;i++)
h[i]=gi(),s.insert(node(i,h[i]));
node pre,nxt,nxtt,pree;
set<node>::iter it,its;
for(int i=1;i<n;i++){
it=--s.lower_bound(node(i,h[i]));
its=s.upper_bound(node(i,h[i]));
pre=*it;
if(pre.x!=-inf)pree=*(--it);
else pree=pre;
nxt=*its;
if(nxt.x!=inf)nxtt=*(++its);
else nxtt=nxt;
while(!q.empty())q.pop();
if(pre.x!=-inf){
q.push(qu(pre.id,abs(pre.x-h[i])));
if(pree.x!=-inf)
q.push(qu(pree.id,abs(pree.x-h[i])));
}
if(nxt.x!=inf){
q.push(qu(nxt.id,abs(nxt.x-h[i])));
if(pree.x!=inf)
q.push(qu(nxtt.id,abs(nxtt.x-h[i])));
}
qu tmp;
for(int j=1;j<=2;j++){
if(q.empty())break;
tmp=q.top();q.pop();
if(j==1)fa[i][0][0]=tmp.id;
else fa[i][0][1]=tmp.id;
}
if(fa[i][0][0])v[i][0][0]=abs(h[i]-h[fa[i][0][0]]);
else v[i][0][0]=0;
if(fa[i][0][1])v[i][0][1]=abs(h[i]-h[fa[i][0][1]]);
else v[i][0][1]=0;
s.erase(s.find(node(i,h[i])));
}
for(int i=1;i<=n;i++){
fa[i][1][0]=fa[fa[i][0][0]][0][1];
fa[i][1][1]=fa[fa[i][0][1]][0][0];
v[i][1][0]=v[fa[i][0][1]][0][0];
v[i][1][1]=v[i][0][1];
}
for(int j=2;j<=limt;j++)
for(int i=1;i<=n;i++){
fa[i][j][0]=fa[fa[i][j-1][0]][j-1][0];
fa[i][j][1]=fa[fa[i][j-1][1]][j-1][1];
v[i][j][0]=v[i][j-1][0]+v[fa[i][j-1][1]][j-1][0];
v[i][j][1]=v[i][j-1][1]+v[fa[i][j-1][1]][j-1][1];
}
solve();Yut();
}
int main()
{
freopen("drive.in","r",stdin);
freopen("drive.out","w",stdout);
work();
return 0;
}