题目链接:http://codeforces.com/contest/522/problem/D
题目大意: 给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查询,输出在这个区间内的两个相等的数的最短距离,如果没有相等的则输出-1.
线段树+扫描线,线段树维护的值是区间的最小值,从后往前扫,然后每次要做的事有两个:
1.判断当前这个位置 i 的数刚刚是不是出现过,假设刚刚出现的位置是 l ,如果出现过,则在线段树中把l这个位置的值更新为 l - i,同时更新包含这个点的区间的最小值.
2.判断有没有以当前这个位置为左端点的查询区间,如果有,就在线段树中查找这个区间里面的最小值.
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<map> 6 #include<list> 7 using namespace std; 8 const int maxn = 500100,INF = 0x7fffff; 9 map<int,int> mp; 10 11 int n,m,A[maxn]; 12 struct node 13 { 14 int d,l,r; 15 }tree[4*maxn]; 16 struct Node 17 { 18 int flag,ans; 19 int l,r; 20 }Q[maxn]; 21 bool cmp(Node a,Node b) 22 { 23 return a.l >= b.l; 24 } 25 void maketree(node *tree,int p) 26 { 27 if(tree[p].l == tree[p].r) 28 { 29 tree[p].d = INF; 30 return ; 31 } 32 int mid = (tree[p].l + tree[p].r) / 2; 33 tree[2*p].l = tree[p].l; 34 tree[2*p].r = mid; 35 tree[2*p+1].l = mid + 1; 36 tree[2*p+1].r = tree[p].r; 37 tree[2*p].d = tree[2*p+1].d = INF; 38 maketree(tree,2*p); 39 maketree(tree,2*p+1); 40 } 41 void update(node *tree,int p,int loc,int d) 42 { 43 if(tree[p].l == tree[p].r) 44 { 45 tree[p].d = min(tree[p].d,d); 46 return ; 47 } 48 int mid = (tree[p].l + tree[p].r) / 2; 49 if(loc <= mid) 50 update(tree,2*p,loc,d); 51 else update(tree,2*p+1,loc,d); 52 tree[p].d = min(tree[p].d,d); 53 } 54 int data_sear; 55 void search(node *tree,int p,int l,int r) 56 { 57 if(tree[p].l == l && tree[p].r == r) 58 { 59 data_sear = min(data_sear,tree[p].d); 60 return ; 61 } 62 int mid = (tree[p].l + tree[p].r) / 2; 63 if(r <= mid) search(tree,2*p,l,r); 64 else if(l <= mid && r > mid) 65 { 66 search(tree,2*p,l,mid); 67 search(tree,2*p+1,mid+1,r); 68 } 69 else if(l > mid) search(tree,2*p+1,l,r); 70 } 71 72 bool cmp2(Node a,Node b) 73 { 74 return a.flag < b.flag; 75 } 76 int main() 77 { 78 while(scanf("%d%d",&n,&m)!=EOF) 79 { 80 for(int i = 1;i <= n;++i) 81 scanf("%d",&A[i]); 82 for(int i = 0;i < m;++i) 83 { 84 scanf("%d%d",&Q[i].l,&Q[i].r); 85 Q[i].flag = i; 86 Q[i].ans = INF; 87 } 88 sort(Q,Q+m,cmp); //按照左端点排好序,方便下面二分查找 89 tree[1].l = 1; 90 tree[1].r = n; 91 tree[1].d = INF; 92 maketree(tree,1); //构建好线段树 93 mp.clear(); 94 int f = 0; //指向当前的查询 95 for(int i = n;i >= 1;--i) 96 { 97 if(mp[A[i]] != 0) 98 update(tree,1,mp[A[i]],mp[A[i]]-i); //更新线段树 99 mp[A[i]] = i; 100 while(f < m && Q[f].l == i) 101 { 102 data_sear = INF; 103 search(tree,1,Q[f].l,Q[f].r); //查询这个区间内的最小值 104 Q[f].ans = (data_sear <= n? data_sear:-1); 105 f++; 106 } 107 } 108 sort(Q,Q+m,cmp2); 109 for(int i = 0;i < m;++i) 110 printf("%d ",Q[i].ans); 111 } 112 return 0; 113 }