这种题考试一定要先打暴力保证50分的暴力分。。。
调试得想吐。。。
最小和次小,倒着跑一边map或set就好了
询问为倍增
qq[i][j]表示从i城市跑2^j轮达到的城市
l[i][j][1]表示从i城市跑2^j轮A的行程
r[i][j][1]表示从i城市跑2^j轮B的行程
转移就好了
#include<cstring>
#include<set>
#include<cmath>
#include<map>
#define For(i,j,k) for(long long i=j;i<=k;i++)
#define Forr(i,j,k) for(long long i=j;i>=k;i--)
using namespace std;
const long long N=100000+5;
const long long inf=50000000000000ll;
map<long long ,long long>q;
map<long long ,long long>::iterator it;
long long h[N],next1[N],next2[N];
long long n,m;
double eps =0.0000001;
int sgn(double x,double y){
if(fabs(x-y)<eps)return 0;
if(x<y)return 1;
return -1;
}
inline long long read(){
char c=getchar();
long long f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
long long x=c-'0';
c=getchar();
while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
return f*x;
}
struct node{
long long a;
long long b;
}temp[5];
long long compare(const node w1,const node w2){
if(w1.a==w2.a)
return w1.b<w2.b;
return w1.a<w2.a;
}
long long compare2(const long long a,const long long b){return a>b;}
void deal(){
Forr(i,n,1){
q[h[i]]=i;
it=q.upper_bound(h[i]);
For(j,1,4)temp[j].a=inf;
if(it!=q.end()){
temp[1].a=abs(h[i]-it->first);temp[1].b=it->first;
it++;
if(it!=q.end())
temp[2].a=abs(h[i]-it->first);temp[2].b=it->first;
}
it=q.lower_bound(h[i]);
if(it!=q.begin()){
it--;
temp[3].a=abs(h[i]-it->first);temp[3].b=it->first;
if(it!=q.begin()){
it--;
temp[4].a=abs(h[i]-it->first);temp[4].b=it->first;
}
}
sort(temp+1,temp+5,compare);
it=q.lower_bound(temp[1].b);
if(temp[1].a!=inf)next1[i]=it->second;
it=q.lower_bound(temp[2].b);
if(temp[2].a!=inf)next2[i]=it->second;
}
}
long long qq[N][25],l[N][25][2];
void pre(){
For(i,1,n)
For(j,0,20)
qq[i][j]=-1;
For(i,1,n)
if(next1[next2[i]]){
qq[i][0]=next1[next2[i]];
l[i][0][1]=abs(h[next2[i]]-h[i]);
l[i][0][2]=abs(h[next1[next2[i]]]-h[next2[i]]);
}
For(j,1,20)
For(i,1,n)
if(qq[i][j-1]!=-1){
qq[i][j]=qq[qq[i][j-1]][j-1];
l[i][j][1]=l[i][j-1][1]+l[qq[i][j-1]][j-1][1];
l[i][j][2]=l[i][j-1][2]+l[qq[i][j-1]][j-1][2];
}
}
void solve1(){
long long tot=read(),k=0;h[0]=-inf;
double ans=2000000005.0;
For(i,1,n){
long long x=i,sum1=0,sum2=0;
Forr(j,20,0)
if(qq[x][j]!=-1&&sum1+sum2+l[x][j][1]+l[x][j][2]<=tot){
sum1+=l[x][j][1];
sum2+=l[x][j][2];
x=qq[x][j];
}
if(sum1+sum2+abs(h[next2[x]]-h[x])<=tot)sum1+=abs(h[next2[x]]-h[x]);
if(sum2==0&&ans==2000000005.0){if(h[i]>h[k])k=i;}
else if(sum2==0)k=k;
else if(sgn(sum1*1.0/sum2,ans)==1){ans=sum1*1.0/sum2;k=i;}
else if(!sgn(sum1*1.0/sum2,ans))if(h[i]>h[k])k=i;
}
cout<<k<<endl;
}
void solve2(long long x,long long y){
long long tot=y;
long long sum1=0,sum2=0;
Forr(j,20,0)
if(qq[x][j]!=-1){
sum1+=l[x][j][1];
sum2+=l[x][j][2];
if(sum1+sum2>tot){sum1-=l[x][j][1];sum2-=l[x][j][2];continue;}
x=qq[x][j];
}
if(sum1+sum2+abs(h[next2[x]]-h[x])<=tot)sum1+=abs(h[next2[x]]-h[x]);
cout<<sum1<<" "<<sum2<<endl;
}
int main(){
n=read();
For(i,1,n)h[i]=read();
deal();
pre();
solve1();
m=read();
long long x,y;
For(i,1,m){x=read();y=read();solve2(x,y);}
return 0;
}