传送门:点击打开链接
题意:n个点告诉你,m次查询,每次查询给l,r,求区间[l,r]里面两个相等的数字的最近的距离是多少。
思路:一般这种没有修改的题,都可以用离线来搞,按照区间右端点排序。然后各个点的值比较大,把它离散一下。
用pre[i]维护上一个节点的位置,然后在线段树中,一个节点维护的是以这个节点作为两个相等的数字的左边那个,最小距离是多少。每次移动右端点时,都更新一下A[pre[A[i]]]]的值,然后询问直接线段树就可以搞定了。
#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;const int MX = 5e5 + 5;
const int INF = 0x3f3f3f3f;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1int MIN[MX << 2];
void push_up(int rt) {MIN[rt] = min(MIN[rt << 1], MIN[rt << 1 | 1]);
}
void update(int x, int d, int l, int r, int rt) {if(l == r) {MIN[rt] = min(MIN[rt], d);return;}int m = (l + r) >> 1;if(x <= m) update(x, d, lson);else update(x, d, rson);push_up(rt);
}
int query(int L, int R, int l, int r, int rt) {if(L <= l && r <= R) {return MIN[rt];}int m = (l + r) >> 1, ret = INF;if(L <= m) ret = min(ret, query(L, R, lson));if(R > m) ret = min(ret, query(L, R, rson));return ret;
}struct Que {int l, r, id;bool operator<(const Que &P) const {return r < P.r;}
} Q[MX];int pre[MX], A[MX], B[MX], ans[MX];int main() {int n, m; //FIN;while(~scanf("%d%d", &n, &m)) {memset(MIN, INF, sizeof(MIN));memset(pre, 0, sizeof(pre));for(int i = 1; i <= n; i++) {scanf("%d", &B[i]);A[i] = B[i];}sort(B + 1, B + 1 + n);int rear = unique(B + 1, B + 1 + n) - B - 1;for(int i = 1; i <= n; i++) {A[i] = lower_bound(B + 1, B + 1 + n, A[i]) - B;}for(int i = 1; i <= m; i++) {scanf("%d%d", &Q[i].l, &Q[i].r);Q[i].id = i;}sort(Q + 1, Q + 1 + m);for(int i = 1, c = 1; i <= n; i++) {if(pre[A[i]]) update(pre[A[i]], i - pre[A[i]], 1, n, 1);while(c <= m && i == Q[c].r) {int Min = query(Q[c].l, Q[c].r, 1, n, 1);ans[Q[c++].id] = Min == INF ? -1 : Min;}pre[A[i]] = i;}for(int i = 1; i <= m; i++) {printf("%d\n", ans[i]);}}return 0;
}