Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)

题目链接: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\n",Q[i].ans);
111     }
112     return 0;
113 }
View Code

 

posted @ 2015-03-12 21:06  xiaxiaosheng  阅读(369)  评论(0编辑  收藏  举报