这不是一道决策选择题目,从每一个点出发,将要经过的路径除了受x值所影响而在长度有变化外,实际上是固定的,这个是倍增的基础

- 从一个节点到另一个节点的长度实则为两个节点权值之差,每个节点的最小点与次小点都位于该节点的右侧

- 题目可以分三部分解决,第一部分用于预处理每个节点右侧最小点与次小点,第二部分用于倍增预处理将时间负复杂度降为O(1),第三部分用于解决问题

**First part**

我采用的标记+Fenwick树+vector求解,可惜常数较大(正解双向链表,O(1)复杂度+极小常数)

- vector按顺序存入每个节点的ID和权值,然后以权值为比较对象进行排序

- 设某节点位置为i,易知每个点的最小点和次小点的位置位于[i-2, i+2] 这个区间中(假设该区间中的所有节点位于该节点的右侧)(当然不是该节点本身)

- 让我们从最左侧节点向右开始寻找,每次确认了最小点和次小点后就将它从vector中erase,即可保证每个节点寻找到的最小值都位于该节点的右侧

- 为了保证查找与erase是从1~n的,我们需要得到每个节点在vector中动态的位置,在这里我采用了Fenwick树获得动态位置

1. 将每个节点的初始位置进行标记,然后每次出vector便在该位置中Fenwick树增加值,值为1

2. 每次要查询某个点,该节点的动态位置为标记位置-标记位置前方已经erase掉的点

- 有一个小细节,当两点的距离相同时海拔较低而优先级高

**Second part**

采用倍增求解(倍增也为正解,也只有倍增为正解)

- 不难发现,从任意节点出发先由A开车,经过2的0次方个点后为B开车,经过2的1次方的点后为A开车,经过2的2次方的点后为A开车...以此类推不需要特判B开车的情况

- 开车经过的总距离为A开车的距离+B开车的距离,开两个数组分别记录即可

- 设可经过路程为X,进入递归函数进行模拟直到总路程最接近X位置

- 有一个小细节,路程可能会爆int所以要开long long

**Third part**

1. 枚举节点然后以X0为距离限制进行判断最优值

2. 取出预存好的查询内容进行查询

- 这一段的细节非常多

截取题面 对于一个给定的 X=X0从哪一个城市出发,小 A 开车行驶的路程总数与小 BB 行驶的路程总数的比值最小(**如果小 B 的行驶路程 0,此时的比值可视为无穷大,且两个无穷大视为相等**)。如果从多个城市出发,小 A 开车行驶的路程总数与小B行驶的路程总数的**比值都最小,则输出海拔最高的那个城市。**

```
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
#include<vector>
#include<time.h>
using namespace std;
inline int in();
inline void put(long long);
void gosearch(int);
void add(int x, int y);
int sum(int x);
int pit(int x) {return x&-x;}

struct Node{
    int high, id;
    Node (int a = 0, int b = 0) : high(a), id(b) {}
    bool operator < (const Node& temp) const {
        return high > temp.high;
    }
};
const int INF = 2147483645;
vector <Node> k;
int n, M, X0;
int high[100100], Si[100100], Xi[100100], fir[100100], sec[100100], mem[100100], Fenwick[100100], maxn[100100];
int Go[100100][20]; long long goAlen[100100][20], goBlen[100100][20];

void go(int ind, long long& tA, long long& tB, int len) {
    for (int j = maxn[ind]; j >= 0; --j) {
        if (Go[ind][j]) {
            if (tA+tB+goAlen[ind][j]+goBlen[ind][j] <= len) {
                tA += goAlen[ind][j];
                tB += goBlen[ind][j];
                go(Go[ind][j], tA, tB, len);
                break;
            }
        }
    }
}
void work() {
    sort(k.begin(), k.end());
    int p = k.size();
    for (int i = 0; i < p; ++i) {
        mem[k[i].id] = i;
    }
    for (int i = 1; i <= n; ++i) {
        gosearch(mem[i]-sum(mem[i]+1));
        add(mem[i]+1, 1);
    }
    for (int i = n; i >= 1; --i) {
        Go[i][0] = sec[i];
        Go[i][1] = fir[sec[i]];
        if (Go[i][0]) goAlen[i][0] = goAlen[i][1] = abs(high[i]-high[sec[i]]);
        if (Go[i][1]) goBlen[i][1] = abs(high[sec[i]]-high[fir[sec[i]]]);
        for (int j = 2; ; ++j) {
            if (!Go[Go[i][j-1]][j-1]) {
                maxn[i] = j-1;
                break;
            }
            Go[i][j] = Go[Go[i][j-1]][j-1];
            goBlen[i][j] = goBlen[Go[i][j-1]][j-1]+goBlen[i][j-1];
            goAlen[i][j] = goAlen[Go[i][j-1]][j-1]+goAlen[i][j-1];
        }
    }
    double eps = (double)INF;
    int ans, maxhigh = -INF;
    for (int i = 1; i <= n; ++i) {
        long long tA = 0, tB = 0;
        go(i, tA, tB, X0);
        if (tB) {
            double fps = 1.0*tA/tB;
            if (fps <= eps) {
                if (fps == eps) {
                    if (high[i] > maxhigh) {
                        maxhigh = high[i];
                        ans = i;
                    }
                } else {
                    eps = fps;
                    ans = i;
                    maxhigh = high[i];
                }
            }
        }
    }
    printf("%d\n", ans);
    for (int i = 1; i <= M; ++i) {
        long long tA = 0, tB = 0;
        go(Si[i], tA, tB, Xi[i]);
        printf("%lld %lld\n", tA, tB);
    }//*//*
}
void input() {
    n = in();
    for (int i = 1; i <= n; ++i) {
        high[i] = in();
        k.push_back(Node(high[i], i));
    }
    X0 = in();
    M = in();
    for (int i = 1; i <= M; ++i) {
        Si[i] = in(); Xi[i] = in();
    }
}
int main() {
    input();
    work();
    //printf("%.4lf", (double)clock()/CLOCKS_PER_SEC);
}
void gosearch(int i) {
    int first = INF, second = INF, firx = 0, secx = 0, e = k[i].high, p = k.size();
    bool flag1 = false, flag2 = false;
    for (int j = i-2; j <= i+2; ++j) {
        if (j < 0 or j == i or j >= p) continue;
        if (abs(k[j].high-e) <= first) {
            flag1 = true;
            first = abs(k[j].high-e);
            firx = k[j].id;
        }
    }
    for (int j = i-2; j <= i+2; ++j) {
        if (j < 0 or j == i or j >= p) continue;
        if (abs(k[j].high-e) <= second and k[j].id != firx) {
            flag2 = true;
            second = abs(k[j].high-e);
            secx = k[j].id;
        }
    }
    if (flag1) fir[k[i].id] = firx;
    if (flag2) sec[k[i].id] = secx;
    k.erase(k.begin()+i);
}
void add(int x, int s) {
    while (x <= n) {
        Fenwick[x] += s;
        x += pit(x);
    }
}
int sum(int x) {
    int tot = 0;
    while (x > 0) {
        tot += Fenwick[x];
        x -= pit(x);
    }
    return tot;
}
inline int in() {
    int ch = getchar(), x = 0, base = 1;
    while (!isdigit(ch)) {
        if (ch == '-') base = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    return x*base;
}

```