CF765F Souvenirs

给出 nn 以及一个长为 nn 的序列 aa

给出 mm,接下来 mm 组询问。

每组询问给出一个 l,rl,r,你需要求出,对于 i,j[l,r]i,j \in [l,r],且满足 iji \neq jaiaj|a_i-a_j| 的最小值。

1n1051 \leq n \leq 10^51m3×1051 \leq m \leq 3\times 10^50ai1090 \leq a_i \leq 10^9

sol

感觉做分块顺手了许多,不到一小时。

首先看到这题类似于第四分块,于是考虑分块。

考虑对序列分块,取块长为 n\sqrt n,便利计算时间复杂度,后续可手动调整。

按照套路,先想区间在同一个块内的答案,块内排序,然后暴力计算即可,时间复杂度 O(n)\mathcal O(\sqrt n)

如果区间不在同一个块,则分为三个部分:左散块,中多整块,右散块(都是套路了吧)。

s[i][j]s[i][j] 表示第 ii 块到第 jj 块的答案,f[i][j]f[i][j] 表示 ii 在块内的 ii 前缀与第 jj 块到 ii 的上一块的答案,g[i][j]g[i][j] 表示 ii 所在块内的 ii 后缀与 ii 的下一块到第 jj 块的答案。

对于中多整块的答案,直接查询 ss 数组,时间复杂度 O(1)\mathcal O(1)

对于左散块及右散块对中间块的答案,直接查询 f,gf,g 数组,时间复杂度 O(1)\mathcal O(1)

对于左、右散块的内部答案,由于排序后是有序的,归并双指针计算即可,时间复杂度 O(n)\mathcal O(\sqrt n)

最后考虑预处理 f,g,sf,g,s

对于 f,gf,g,先计算每个数与每个块的答案,然后前、后缀一下即可,时间复杂度为 O(nn)\mathcal O(n \sqrt n)(注意此时有序,使用双指针优化,时间复杂度不会达到 O(n2)\mathcal O(n^2))。

那么 ss 可由 ff 递推而来,时间复杂度 O(n)\mathcal O(n)

那么总时空复杂度为 O(nn)\mathcal O(n\sqrt n)

注意,代码中 ff 数组是把上面的 f,gf,g 结合成的,优化空间。

45.72s / 124.22MB / 3.90KB C++20 O2\text{45.72s / 124.22MB / 3.90KB C++20 O2},稍逊于线段树,不过优势是可强制在线。

#include <bits/stdc++.h>

using namespace std;

#define re register

inline int read()
{
    re int x = 0, f = 1;
    re char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
        x = x * 10 + c - '0', c = getchar();
    return x * f;
}

inline void write(re int x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

inline void cmin(int &a, int b)
{
    a = b > a ? a : b;
}

const int _ = 1e5 + 2, BEL = 320;

int n, m, a[_], blo, ans[_];

int f[_][BEL], s[BEL][BEL], L[BEL], R[BEL];

pair<int, int> b[_];

vector<int> vl, vr;

inline int merge()
{
    re int l1 = 0, l2 = 0, ans = 0x3f3f3f3f;
    for (re int i = 0; i < vl.size() - 1; ++i)
        cmin(ans, vl[i + 1] - vl[i]);
    for (re int i = 0; i < vr.size() - 1; ++i)
        cmin(ans, vr[i + 1] - vr[i]);
    while (l1 < vl.size() && l2 < vr.size())
    {
        cmin(ans, abs(vl[l1] - vr[l2]));
        if (vl[l1] < vr[l2])
            ++l1;
        else
            ++l2;
    }
    return ans;
}

signed main()
{
    n = read();
    for (re int i = 1; i <= n; ++i)
        a[i] = read(), b[i] = {a[i], i};
    blo = (n - 1) / BEL + 1;
    for (re int i = 1; i <= blo; ++i)
        L[i] = R[i - 1] + 1, R[i] = i * BEL;
    R[blo] = n;
    for (re int i = 1; i <= blo; ++i)
        sort(b + L[i], b + R[i] + 1);
    for (re int i = 1; i <= blo; ++i)
    {
        for (re int j = 1; j <= blo; ++j)
            if (i != j)
                for (re int k = L[i], l = L[j]; k <= R[i]; ++k)
                {
                    while (l < R[j] && b[l + 1].first < b[k].first)
                        ++l;
                    f[b[k].second][j] = abs(b[k].first - b[l].first);
                    if (l < R[j])
                        cmin(f[b[k].second][j], abs(b[l + 1].first - b[k].first));
                }
        for (re int k = L[i]; k <= R[i]; ++k)
        {
            for (re int j = i - 2; j >= 0; --j)
                cmin(f[k][j], f[k][j + 1]);
            for (re int j = i + 2; j <= blo; ++j)
                cmin(f[k][j], f[k][j - 1]);
        }
        for (re int j = 1; j < i; ++j)
            for (re int k = L[i] + 1; k <= R[i]; ++k)
                cmin(f[k][j], f[k - 1][j]);
        for (re int j = i + 1; j <= blo; ++j)
            for (re int k = R[i] - 1; k >= L[i]; --k)
                cmin(f[k][j], f[k + 1][j]);
        s[i][i] = 0x3f3f3f3f;
        for (re int j = L[i]; j < R[i]; ++j)
            cmin(s[i][i], b[j + 1].first - b[j].first);
    }
    for (re int i = 1; i <= blo; ++i)
        for (re int j = i + 1; j <= blo; ++j)
            s[i][j] = min(min(s[i][j - 1], f[R[j]][i]), s[j][j]);
    m = read();
    re int l, r, bl, br, ans;
    while (m--)
    {
        l = read(), r = read();
        bl = (l - 1) / BEL + 1, br = (r - 1) / BEL + 1;
        ans = 0x3f3f3f3f;
        if (bl < br)
        {
            if (bl + 1 <= br - 1)
            {
                ans = s[bl + 1][br - 1];
                cmin(ans, min(f[r][bl + 1], f[l][br - 1]));
            }
            vl.clear(), vr.clear();
            for (re int i = L[bl]; i <= R[bl]; ++i)
                if (b[i].second >= l)
                    vl.push_back(b[i].first);
            for (re int i = L[br]; i <= R[br]; ++i)
                if (b[i].second <= r)
                    vr.push_back(b[i].first);
            cmin(ans, merge());
        }
        else
        {
            re int lst = -0x3f3f3f3f;
            for (re int i = L[bl]; i <= R[bl]; ++i)
                if (l <= b[i].second && b[i].second <= r)
                {
                    cmin(ans, b[i].first - lst);
                    lst = b[i].first;
                }
        }
        printf("%d\n", ans);
    }
}
posted @ 2022-03-30 13:56  蒟蒻orz  阅读(1)  评论(0编辑  收藏  举报  来源