题面:
题目大意
给出一个序列,每次查询一段区间内距离最近的相同元素之间的距离.
思路:
由于只有两个相同的数在查询区间才会对答案产生贡献
用一个
p
r
e
[
i
]
pre[i]
pre[i] 来记录和
a
[
i
]
a[i]
a[i]相同的数上一次出现的位置
这两个相同的数产生的贡献就是
w
=
i
−
p
r
e
[
i
]
w = i - pre[i]
w=i−pre[i]
我们把这个贡献放在
p
r
e
[
i
]
pre[i]
pre[i]这个位置上。
那我们要查询[l,r]的答案,这就是区间求最小值问题了
但是我们这里还有一个问题就是:
我们查询
[
l
,
r
]
[l,r]
[l,r]的到答案,无法确定这个答案是不是
i
i
i 在
r
r
r 后面,
p
r
e
[
i
]
pre[i]
pre[i] 在
[
l
,
r
]
[l,r]
[l,r]这种情况产生的贡献。所以我们离线来做,去避免这种情况。
贡献最小值用线段树来维护。
先将询问都存下来,然后从前往后遍历原序列,当能产生贡献时,用线段树更新,当遍历到询问的
r
r
r ,用线段树查询
[
l
,
r
]
[l,r]
[l,r]区间最小值。
代码:
#include <bits/stdc++.h>
#define ll long long
#define ls u<<1
#define rs u<<1|1
using namespace std;
const int N = 5e5 + 5, INF = 0x3f3f3f3f;
int n, m;
int a[N], pre[N];
map<int, int>mp;
int ans[N];
struct node {
int l, r, v, lazy;
}tr[N * 4];
vector<pair<int, int> >g[N];
void pushup(int u) {
tr[u].v = min(tr[ls].v, tr[rs].v);
}
void pushdown(int u) {
if (tr[u].lazy != INF) {
int v = tr[u].lazy;
tr[ls].lazy = min(tr[ls].lazy, v);
tr[rs].lazy = min(tr[rs].lazy, v);
tr[ls].v = min(tr[ls].v, v);
tr[rs].v = min(tr[rs].v, v);
tr[u].lazy = INF;
}
}
void build(int u, int l, int r) {
tr[u] = { l,r,INF,INF };
if (l == r) return;
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
}
void update(int u, int l, int r, int v) {
if (tr[u].l >= l && tr[u].r <= r) {
tr[u].v = min(tr[u].v, v);
tr[u].lazy = min(tr[u].lazy, v);
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) update(ls, l, r, v);
if (r > mid) update(rs, l, r, v);
pushup(u);
}
int query(int u, int l, int r) {
if (tr[u].l >= l && tr[u].r <= r) {
return tr[u].v;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
int r1 = INF, r2 = INF;
if (l <= mid) r1 = query(ls, l, r);
if (r > mid) r2 = query(rs, l, r);
return min(r1, r2);
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
if (!mp.count(a[i])) {
pre[i] = i;
mp[a[i]] = i;
}
else {
pre[i] = mp[a[i]];
mp[a[i]] = i;
}
}
for (int i = 1; i <= m; i++) {
int l, r;
cin >> l >> r;
g[r].push_back({ l, i });
}
build(1, 1, n);
for (int i = 1; i <= n; i++) {
int v = i - pre[i];
if (v > 0) {
update(1, pre[i], pre[i], v);
}
for (auto [l, id] : g[i]) {
int res = query(1, l, i);
ans[id] = res == INF ? -1 : res;
}
}
for (int i = 1; i <= m; i++) cout << ans[i] << "\n";
return 0;
}