Souvenirs

Souvenirs

首先离线,考虑每一个点维护后面的点和它绝对值的最小值,那么答案就是一段后缀 \(\min\),这个可以用树状数组来维护。那么现在的问题就是加入一个数,去更新前面的状态,假设现在加入了 \(a_i\),我们只考虑\(j < i, a_j > a_i\)的情况,对于\(a_j < a_i\)是对称的。

找到一个最大的\(j\)是容易的,用权值线段树维护即可,但暴力去找每个\(j\)是不优的,去刻画下一个能更新后缀最小值的位置\(k\),有条件 \(a_k - a_i < a_j - a_k\),因为\(j\)是能更新\(k\)的。

发现\(a_k < \frac{1}{2}(a_i + a_j)\),这样\(a_k\)会在\(O(\log V)\)的次数下接近\(a_i\)
这样总时间复杂度为\(O(n\log^2V)\)\(V\)是值域。

Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#define IN inline
using namespace std;
const int N = 1e5 + 5, inf = 1e9;
int ls[N * 30], rs[N * 30], f[N * 30], n, Q, a[N], g[N], siz, ans[N << 2];

IN int read() {
	int t = 0,res = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) t |= (ch == '-');
	for (; isdigit(ch); ch = getchar()) res = (res << 3) + (res << 1) + (ch ^ 48);
	return t ? -res : res;
}
struct qy{int l, r, id;}b[N << 2];
bool cmp(qy x, qy y){return x.r < y.r;}
int lowbit(int x){return x & -x;}
void add(int x, int v){for (; x; x -= lowbit(x)) g[x] = min(g[x], v);}
int getans(int x) {
	int res = 1e9;
	for (; x <= n; x += lowbit(x)) res = min(res, g[x]);
	return res;
}
void update(int &p, int l, int r, int u, int v) {
	if (!p) p = ++siz; f[p] = v;
	if (l == r) return; int mid = l + r >> 1;
	if (u <= mid) update(ls[p], l, mid, u, v);
	else update(rs[p], mid + 1, r, u, v);
}
int query(int p, int l, int r, int L, int R) {
	if (!p) return 0;
	if (L <= l && r <= R) return f[p];
	int mid = l + r >> 1, res = 0; 
	if (L <= mid) res = query(ls[p], l, mid, L, R);
	if (R > mid) res = max(res, query(rs[p], mid + 1, r, L, R));
	return res;
}
void solve() {
	int rt = 0;
	for (int i = 1; i <= siz; i++) f[i] = ls[i] = rs[i] = 0;
	for (int i = 1; i <= n; i++) g[i] = 1e9; 
	siz = 0;
	for (int i = 1, j = 1; i <= Q; i++) {
		while (j <= n && j <= b[i].r) {
			int u = query(rt, 0, inf, a[j], inf);
			while (u) {
				add(u, a[u] - a[j]);
				if (a[u] == a[j]) break;
				u = query(rt, 0, inf, a[j], (a[j] + a[u]) / 2);
			}
			update(rt, 0, inf, a[j], j), j++;
		}
		ans[b[i].id] = min(ans[b[i].id], getans(b[i].l));
	}
}
int main() {
	n = read();
	for (int i = 1; i <= n; i++) a[i] = read();
	Q = read();
	for (int i = 1; i <= Q; i++) b[i] = qy{read(), read(), i}, ans[i] = inf;
	sort(b + 1, b + 1 + Q, cmp), solve();
	for (int i = 1; i <= n; i++) a[i] = inf - a[i];
	solve();
	for (int i = 1; i <= Q; i++) printf("%d\n", ans[i]);
}

posted @ 2023-03-15 21:57  RiverSheep  阅读(86)  评论(0)    收藏  举报