[Codeforces765F] Souvenirs
作者:互联网
\[\min_{i, j \in [l, r], i \not=j}|a_i - a_j| \]
- 给定长度为 \(n\) 的序列 \(a_n\),回答 \(m\) 次询问,每次询问给出 \(l, r\),求
- \(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