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;
}