题解 P1081 【开车旅行】

· · 题解

这里提供另外一种预处理(最小、次小)的方法

用的是之前自己YY出来的树状数组+二分查找,有时候挺好用的,何况我不会数据结构qwq
值域树状数组肯定是单调的,所以可以二分
用这种方法可以实现一个容器
支持插入、删除一个数,以及查询第K大乃至某个给定范围内的数中的第K大
插入、删除正常做
查询时找出容器中满足在查询区间内的数值的范围,就能推出要查的数在数组里的位置了
位置是由单点的sum值体现的,二分查找就行了
只不过这种方法查询是 log^{2}n 的,以及要求离散化,不过这题够用了
这题的预处理实现方式就是倒过来插值,同时查询,总共 O(nlog^{2}n)
然而这题是在考倍增关于倍增各位讲得很清楚了qwq
代码贴这,写了好久啊orz

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const double eps  = 0.0000001;
const double feps = -0.0000001;
const double inf  = 100000000000000000.0;
const int MAXN = 100005;

struct node {
    int g, h; // g: position, h: rank
} P[MAXN];
int N, H[MAXN], poi[MAXN];
int A[MAXN], B[MAXN], C[MAXN];
int D[MAXN][23];
ll dis[MAXN][23][2]; // 0: A, 1: B 

int abs(int x) { return x>0 ? x : -x; }
ll read()
{
    ll o = 0, oo = 0; char c = getchar();
    while (c < '0' || c > '9') oo |= (c=='-'), c = getchar();
    while (c >='0' && c <='9') o = (o<<3)+(o<<1)+(c&15), c = getchar();
    return oo ? -o : o;
}
int cmp1(node x, node y) { return x.h < y.h; }
int cmp2(node x, node y) { return x.g < y.g; }
void add(int x) { for (; x<=N; x+=x&(-x)) C[x] += 1; return; }
int sum(int x) { int res=0; for (; x; x-=x&(-x)) res += C[x]; return res; }
void init()
{
    N = read();
    for (int i=1; i<=N; i++) H[i] = read(), P[i] = (node){i, H[i]};
    sort(P+1, P+N+1, cmp1);
    for (int i=1; i<=N; i++) H[i] = P[i].h, poi[i] = P[i].g, P[i].h = i;
    sort(P+1, P+N+1, cmp2);

    A[N] = B[N] = 0, add(P[N].h);
    A[N-1] = 0, B[N-1] = N, add(P[N-1].h);
    for (int i=N-2; i>=1; i--)
    {
        int l, r, m, t=sum(P[i].h), a, b, c;

        if (t > 0) {
            l = 0, r = P[i].h; // (l, r]
            while (r - l > 1) {
                m = (l + r) >> 1;
                if (sum(m) < t) l = m; else r = m;
            }
            a = r;
        } else { a = 0; }
        if (t < N-i) {
            l = P[i].h, r = N; // (l, r]
            while (r - l > 1) {
                m = (l + r) >> 1;
                if (sum(m) > t) r = m; else l = m;
            }
            b = r;
        } else { b = 0; }
        if (!a) { B[i] = poi[b], c = 0; }
        if (!b) { B[i] = poi[a], c = 0; }
        if (a&&b) {
            int da = abs(H[P[i].h] - H[a]);
            int db = abs(H[P[i].h] - H[b]);
            B[i] = (da > db) ? poi[b] : poi[a];
            c = (da > db) ? a : b;
        }

        if (t > 1) {
            l = 0, r = P[i].h; // (l, r]
            while (r - l > 1) {
                m = (l + r) >> 1;
                if (sum(m) < t-1) l = m; else r = m;
            }
            a = r;
        } else { a = 0; }
        if (t < N-i-1) {
            l = P[i].h, r = N; // (l, r]
            while (r - l > 1) {
                m = (l + r) >> 1;
                if (sum(m) < t+2) l = m; else r = m;
            }
            b = r;
        } else { b = 0; }
        int da = abs(H[P[i].h] - H[a]);
        int db = abs(H[P[i].h] - H[b]);
        int dc = abs(H[P[i].h] - H[c]);
        if (c) {
            if (a) c = (da > dc) ? c : a;
            if (b) c = (dc > db) ? b : c;
        } else {
            if (a) c = a;
            if (b) c = b;
        }
        A[i] = poi[c];

        add(P[i].h);
    }

    for (int i=1; i<=N; i++) {
        D[i][0] = B[A[i]];
        dis[i][0][0] = abs(H[P[A[i]].h] - H[P[i].h]);
        dis[i][0][1] = abs(H[P[B[A[i]]].h] - H[P[A[i]].h]);
    }
    for (int j=1; j<=21; j++) {
        for (int i=1; i<=N; i++) {
            D[i][j] = D[D[i][j-1]][j-1];
            dis[i][j][0] = dis[i][j-1][0] + dis[D[i][j-1]][j-1][0];
            dis[i][j][1] = dis[i][j-1][1] + dis[D[i][j-1]][j-1][1];
        }
    }

    return;
}
void work()
{
    double T = inf, t;
    int S = 1;
    ll M = read(), m, LA, LB;

    for (int i=1; i<=N; i++) {
        LA = 0, LB = 0, m = M;
        int o = i;
        for (int j=21; j>=0; j--) if (D[o][j]) {
            if (dis[o][j][0] + dis[o][j][1] <= m) {
                m -= dis[o][j][0] + dis[o][j][1];
                LA += dis[o][j][0], LB += dis[o][j][1];
                o = D[o][j];
            }
        }
        if (A[o] && abs(H[P[o].h] - H[P[A[o]].h]) <= m)
            LA += abs(H[P[o].h] - H[P[A[o]].h]);
        if (LB > 0) {
            t = (double) LA / LB;
            if (t < T) T = t, S = i;
            else if (t-T<eps&&t-T>feps) S = H[P[i].h] > H[P[S].h] ? i : S;
        } else if (T + 1.0 > inf) S = H[P[i].h] > H[P[S].h] ? i : S;
    }
    printf("%d\n", S);

    M = read();
    for (; M; M--)
    {
        S = read(), m = read(), LA = 0, LB = 0;
        int o = S;
        for (int j=21; j>=0; j--) if (D[o][j]) {
            if (dis[o][j][0] + dis[o][j][1] <= m) {
                m -= dis[o][j][0] + dis[o][j][1];
                LA += dis[o][j][0], LB += dis[o][j][1];
                o = D[o][j];
            }
        }
        if (A[o] && abs(H[P[o].h] - H[P[A[o]].h]) <= m)
            LA += abs(H[P[o].h] - H[P[A[o]].h]);

        printf("%lld %lld\n", LA, LB);
    }

    return;
}
int main()
{
//  freopen("", "r", stdin);
//  freopen("", "w", stdout);
    init();
    work();
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}