//戳这里:522D
思路:为了简化问题我们先确定区间的右端,则需要先从右端最靠左的区间开始处理;处理某个区间时,我们将元素从 1 的位置处理到这个区间的右端(得到每个元素在其右侧最近相同元素的距离),然后只需要从这个区间的左端遍历到右端就能得到这个区间内的解。如果熟悉树状数组性质的话可以方便的把这个 O(n) 的遍历过程,优化成O(logn)。
//PS:用线段树代码貌似会长很多...
1 #include "bits/stdc++.h" 2 using namespace std; 3 const int maxn = 5e5 + 5; 4 const int INF = 0x3f3f3f3f; 5 int n, m; 6 int ans[maxn], order[maxn], l[maxn], r[maxn]; 7 int res[maxn]; 8 map<int , int> mp; 9 int tr[maxn]; 10 11 bool cmp(int a, int b) 12 { 13 return r[a] < r[b]; 14 } 15 16 int main() 17 { 18 int i, j; 19 scanf("%d%d", &n ,&m); 20 for(i = 1; i <= n; ++i) { 21 scanf("%d", &ans[i]); 22 } 23 for(i = 1; i <= m; ++i) { 24 scanf("%d%d", &l[i], &r[i]); 25 order[i] = i; 26 } 27 28 memset(tr, 0x3f, sizeof(tr)); 29 memset(res, 0x3f, sizeof(res)); 30 sort(order + 1, order + 1 + m, cmp); 31 for(i = j = 1; i <= m; ++i) { 32 int o = order[i]; 33 while(j <= r[o]) { 34 if(mp[ans[j]]) { 35 int pos = mp[ans[j]]; 36 for(int k = pos; k; k -= k&-k) 37 tr[k] = min(tr[k], j - pos); 38 } 39 mp[ans[j]] = j; 40 ++j; 41 } 42 for(int k = l[o]; k <= r[o]; k += k&-k) 43 res[o] = min(res[o], tr[k]); 44 } 45 for(i = 1; i <= m; ++i) 46 printf("%d ", res[i] == INF? -1: res[i]); 47 }