[NOIP 2012] 开车旅行
题意:
题解:
set+倍增。
这题是一个高效模拟题,所以一般都要用一些比较高效的算法,小A和小B的路线都是固定的,所以很容易想到倍增来高效查询路线。
那么设:
g[i][j]表示从i开始往后\(2^j\)轮,车开到的城市。
f[i][j][0]表示从i开始往后\(2^j\)轮,小A开车的路程。
f[i][j][1]表示从i开始往后\(2^j\)轮,小B开车的路线。
首先预处理出走一轮的路线,这个可以用set来实现。
然后倍增转移。
对于第一问,直接暴枚每个点为起点,比较一下即可。
对于第二问,同理直接查询。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#define ll long long
#define N 100010
using namespace std;
int h[N],g[N][22],f[N][22][2],dis[N][2],to[N][2];
set<int> q;
map<int,int> mp;
int gi() {
int x=0,o=1; char ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') o=-1,ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return o*x;
}
void update(int x, int y) {
int a=mp[x],b=mp[y],d=abs(x-y);
if(!to[a][0] || d<dis[a][0] || (d==dis[a][0] && y<h[to[a][0]])) {
to[a][1]=to[a][0],dis[a][1]=dis[a][0];
to[a][0]=b,dis[a][0]=d;
}
else if(!to[a][1] || d<dis[a][1] || (d==dis[a][1] && y<h[to[a][0]])) {
to[a][1]=b,dis[a][1]=d;
}
}
void query(int x, int len, ll &a, ll &b) {
for(int i=20; i>=0; i--) {
if(g[x][i] && f[x][i][0]+f[x][i][1]<=len) {
a+=f[x][i][0];
b+=f[x][i][1];
len-=f[x][i][0]+f[x][i][1];
x=g[x][i];
}
}
if(to[x][1] && dis[x][1]<=len) a+=dis[x][1];
}
int main() {
int n=gi(),m,x,len,ans;
ll ansa=0,ansb=0,a,b;
for(int i=1; i<=n; i++) mp[h[i]=gi()]=i;
for(int i=n; i>=1; i--) {
q.insert(h[i]);
set<int>::iterator it;
it=q.find(h[i]);
if(it!=q.begin()) {
it--;
update(h[i],*it);
if(it!=q.begin()) {it--,update(h[i],*it),it++;}
it++;
}
if((++it)!=q.end()) {
update(h[i],*it);
if((++it)!=q.end()) update(h[i],*it);
}
}
for(int i=1; i<=n; i++) {
g[i][0]=to[to[i][1]][0];
f[i][0][0]=dis[i][1];
f[i][0][1]=dis[to[i][1]][0];
}
for(int j=1; j<=20; j++)
for(int i=1; i<=n; i++) {
g[i][j]=g[g[i][j-1]][j-1];
f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];
f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];
}
len=gi();
for(int i=1; i<=n; i++) {
a=0,b=0;
query(i,len,a,b);
if(b && (!ansb || a*ansb<b*ansa || (a*ansb==b*ansa && h[i]>h[ans]))) ans=i,ansa=a,ansb=b;
}
printf("%d\n", ans);
m=gi();
while(m--) {
x=gi(),len=gi(),a=0,b=0;
query(x,len,a,b);
printf("%lld %lld\n", a,b);
}
return 0;
}