预备知识——关于set的用法

定义:set<int>s;</int>

本题需要用到的几个函数:

s.insert(x);//插入x
s.lower_bound(x);//查找**大于等于**x的最小元素,返回迭代器
s.upper_bound(x);//查找**大于**x的最小元素,返回迭代器

在本题运用set能够使初始化的复杂度降到O(nlogn)

s.insert(h[i]);
t[1].h=*--s.lower_bound(h[i]);
t[3].h=*--s.lower_bound(t[1].h); 
t[2].h=*s.upper_bound(h[i]); 
t[4].h=*s.upper_bound(t[2].h);
for(int j=1;j<=4;j++)t[j]._abs=abs(t[j].h-h[i]);
sort(t+1,t+5,cmp);
a[i]=t[2]._abs;f
a[i]=mp[t[2].h];
b[i]=t[1]._abs;fb[i]=mp[t[1].h];
if(fa[i])sa[i][0]=a[i],f[i][0]=fa[i];
if(fb[fa[i]])sa[i][1]=a[i],sb[i][1]=b[fa[i]],f[i][1]=fb[fa[i]];

回归正题,由于本题木有修改操作,并且到每个点的下一个点的位置确定,很容易想到倍增来优化,同时由于本题的需要,除f[i][j]外,在定义两个数组sa[i][j]和sb[i][j]],分别表示第i个点走2^j天A所走的路程和B所走的路程。

废话少说,直接上代码:

#include<bits/stdc++.h>
#define INF 50000000000LL
#define A 100005
using namespace std;
struct note{
    long long h,_abs;
}t[5];
set<long long>s;
map<long long,long long>mp;
long long n,h[A],a[A],b[A],fa[A],fb[A],sa[A][25],sb[A][25],f[A][25];
bool cmp(note aa,note bb){
    return (aa._abs==bb._abs?aa.h<bb.h:aa._abs<bb._abs);
}
void st(){
    for(long long i=n;i>=1;i--){
        s.insert(h[i]);
        t[1].h=*--s.lower_bound(h[i]);
        t[3].h=*--s.lower_bound(t[1].h); 
        t[2].h=*s.upper_bound(h[i]); 
        t[4].h=*s.upper_bound(t[2].h);
        for(long long j=1;j<=4;j++)t[j]._abs=abs(t[j].h-h[i]);
        sort(t+1,t+5,cmp);
        a[i]=t[2]._abs;fa[i]=mp[t[2].h];
        b[i]=t[1]._abs;fb[i]=mp[t[1].h];
        if(fa[i])sa[i][0]=a[i],f[i][0]=fa[i];
        if(fb[fa[i]])sa[i][1]=a[i],sb[i][1]=b[fa[i]],f[i][1]=fb[fa[i]];
        for(long long j=2;j<=16;j++)
            if(f[f[i][j-1]][j-1]){
                sa[i][j]=sa[i][j-1]+sa[f[i][j-1]][j-1];
                sb[i][j]=sb[i][j-1]+sb[f[i][j-1]][j-1];
                f[i][j]=f[f[i][j-1]][j-1];
            }
            else break;
    }
}
double ask1(long long x,long long p){
    long long s1=0,s2=0;
    for(long long i=16;i>=0;i--){
        if(f[x][i]&&s1+s2+sa[x][i]+sb[x][i]<=p){
            s1+=sa[x][i];
            s2+=sb[x][i];
            x=f[x][i];
        }
    }
    return (s2==0?INF:(double)s1/(double)s2);
}
void ask2(long long x,long long p){
    long long s1=0,s2=0;
    for(long long i=16;i>=0;i--){
        if(f[x][i]&&s1+s2+sa[x][i]+sb[x][i]<=p){
            s1+=sa[x][i];
            s2+=sb[x][i];
            x=f[x][i];
        }
    }
    if(fa[x]&&s1+s2+sa[x][0]<=p)s1+=sa[x][0];
    printf("%lld %lld\n",s1,s2);
}
void solve(){ 
    double minn=INF;
    long long bj,x0;
    scanf("%lld",&x0);
    for(long long i=1;i<=n;i++){
        double op=ask1(i,x0);
        if(op<minn)minn=op,bj=i;
    }
    printf("%lld\n",bj);
    long long m,s0;
    scanf("%lld",&m);
    while(m--){
        scanf("%lld%lld",&s0,&x0);
        ask2(s0,x0);
    }
}
int main(){
    s.insert(INF);s.insert(INF-1);s.insert(-INF);s.insert(-INF+1);
    scanf("%lld",&n);
    for(long long i=1;i<=n;i++)scanf("%lld",&h[i]),mp[h[i]]=i;
    st();
    solve();
    return 0;
}

结束语:此题不要想得太难,就是一道LCA的加强版,然后在初始化时加上set或链表(本蒟蒻不懂大佬写的链表,所以只有写set了)