其他分享
首页 > 其他分享> > [Codeforces765F] Souvenirs

[Codeforces765F] Souvenirs

作者:互联网

  • 给定长度为 \(n\) 的序列 \(a_n\),回答 \(m\) 次询问,每次询问给出 \(l, r\),求

\[\min_{i, j \in [l, r], i \not=j}|a_i - a_j| \]

  • \(1 \leq n \leq 10^5, 1 \leq m \leq 3 \times 10^5, 0 \leq a_i \leq 10^9\)。

将询问离线,考虑维护固定右端点时每个左端点的答案。

容易发现这个答案是单调不降的,把答案相等的看成一段,整个区间可以分割成不相交的一些段。

当右端点 \(r \rightarrow r + 1\) 时,只需要考虑 \(a_{r + 1}\) 的影响。

这时可以看成删除原来右边的一些段,然后添加一些新段。

新段的数量一定不会很多:

考虑相邻的两个新段,设他们的答案分别为 \(A = |a_i - a_r|, B = |a_j - a_r|,A < B\)。

显然有

\[\begin{aligned} A &< |a_i - a_j|\\ B - A &< B - |a_i - a_j|\\ &= |a_j - a_r| - |a_i - a_j|\\ &\leq |a_i - a_r|\\ &= A \end{aligned} \]

所以 \(2A < B\)。

段数最多只有 \(\log\) 级别。

删除的总段数和新增的总段数是同级的。

所以用线段树暴力维护这个区间的有序数组,修改时候直接二分暴力修改,总复杂度 \(O(n\log^2 n \log a + m \log n)\)。

#include <bits/stdc++.h>
#define dbg(...) std::cerr << "\033[32;1m", fprintf(stderr, __VA_ARGS__), std::cerr << "\033[0m";
template <class T, class U>
inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
template <class T, class U>
inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }

using LL = long long;
using PII = std::pair<int, int>;

constexpr int N(1e5 + 5);
int n, m, a[N];
struct Node {
  std::vector<int> v;
  int min;
} t[N << 2];
#define ls o << 1
#define rs o << 1 | 1
void build(int o, int l, int r) {
  t[o].min = 1e9;
  if (l == r) {
    t[o].v = { a[l] };
    return;
  }
  int m = l + r >> 1;
  build(ls, l, m), build(rs, m + 1, r);
  t[o].min = 1e9;
  t[o].v.resize(r - l + 1);
  std::merge(t[ls].v.begin(), t[ls].v.end(), t[rs].v.begin(), t[rs].v.end(), t[o].v.begin());
}
int now;
void update(int o, int l, int r, int x) {
  if (r < x) {
    auto it = std::upper_bound(t[o].v.begin(), t[o].v.end(), a[x]);
    if (it != t[o].v.end()) {
      smin(t[o].min, *it - a[x]);
    }
    if (it != t[o].v.begin()) {
      smin(t[o].min, a[x] - *--it);
    }
    if (now <= t[o].min) {
      return;
    }
    if (l == r) {
      smin(now, t[o].min);
      return;
    }
  }
  int m = l + r >> 1;
  if (m < x - 1) {
    update(rs, m + 1, r, x);
  }
  update(ls, l, m, x);
  smin(t[o].min, t[ls].min);
  smin(t[o].min, t[rs].min);
  smin(now, t[o].min);
}
int ask(int o, int l, int r, int x, int y) {
  if (x > r || y < l) {
    return 1e9;
  }
  if (x <= l && r <= y) {
    return t[o].min;
  }
  int m = l + r >> 1;
  return std::min(ask(ls, l, m, x, y), ask(rs, m + 1, r, x, y));
}
std::vector<PII> q[N];
int ans[N * 3];
int main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  std::cin >> n;
  for (int i = 1; i <= n; i++) std::cin >> a[i];
  build(1, 1, n);
  std::cin >> m;
  for (int i = 1; i <= m; i++) {
    int x, y; std::cin >> x >> y;
    q[y].emplace_back(x, i);
  }
  for (int i = 2; i <= n; i++) {
    now = 1e9;
    update(1, 1, n, i);
    for (auto [x, t] : q[i]) {
      ans[t] = ask(1, 1, n, x, i);
    }
  }
  for (int i = 1; i <= m; i++) {
    std::cout << ans[i] << "\n";
  }
  return 0;
}

标签:std,Codeforces765F,int,min,Souvenirs,leq,ls,smin
来源: https://www.cnblogs.com/HolyK/p/14237900.html