【NOIP2012】开车旅行

题目描述

小 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\n",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\n",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;
}

posted @ 2017-09-12 16:10  PIPIBoss  阅读(268)  评论(0编辑  收藏  举报