CF522D Closest Equals 离线扫描 + 线段树

CF522D Closest Equals

题意:m 个询问,求 [l,r] 内相同元素的最小距离。
离线询问,按右端点排序。
对于每一个 a[i],如果 last[a[i]] 存在,将线段树 last[a[i]] 的位置改为 i - last[a[i]]。
查询区间最小值。
当然这题也可以回滚莫队。
注:本题一路从黑题堕落到绿题

#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
#define per(i, a, b) for(int i = (a); i >= (b); -- i)
#define pb emplace_back
#define All(X) X.begin(), X.end()
using namespace std;
using ll = long long;
mt19937 rnd(time(0));
constexpr int N = 5e5 + 5, inf = 0x3f3f3f3f; 

int n, m, a[N], b[N], ans[N], lst[N];
vector<pair<int, int>> qr[N];

int t[N << 2];
void modify(int p, int v, int x = 1, int l = 1, int r = n) {
	if(l == r) return t[x] = v, void();
	int mid = l + r >> 1;
	if(p <= mid) modify(p, v, x << 1, l, mid);
	else modify(p, v, x << 1 | 1, mid + 1, r);
	t[x] = min(t[x << 1], t[x << 1 | 1]);
}

int query(int L, int R, int x = 1, int l = 1, int r = n) {
	if(L <= l && r <= R) return t[x];
	int ret = inf;
	int mid = l + r >> 1;
	if(mid >= L) ret = min(ret, query(L, R, x << 1, l, mid));
	if(mid < R) ret = min(ret, query(L, R, x << 1 | 1, mid + 1, r));
	return ret;
}

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> m;
	rep(i, 1, n) cin >> a[i], b[i] = a[i];
	sort(b + 1, b + n + 1);
	int tot = unique(b + 1, b + n + 1) - b - 1;
	rep(i, 1, n) a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
	rep(i, 1, m) {
		int l, r; cin >> l >> r;
		qr[r].pb(l, i);
	}
	memset(t, 0x3f, sizeof t);
	rep(i, 1, n) {
		if(lst[a[i]]) modify(lst[a[i]], i - lst[a[i]]);
		for(auto [l, id] : qr[i]) {
			ans[id] = query(l, i);
			if(ans[id] == inf) ans[id] = -1;
		}
		lst[a[i]] = i;
	}
	rep(i, 1, m) cout << ans[i] << '\n';
	return 0;
}
posted @ 2024-02-03 19:13  Lu_xZ  阅读(4)  评论(0编辑  收藏  举报