zoj 3633 ——线段树

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3633

给你n个数,然后m个询问,每次询问区间[a,b]中从右到左最先出现重复的数字,比如

5
1 2 3 1 2

询问[1 5],那么答案就是2.因为2是第一次出现2次的。其中 3≤ n ≤ 500,000,1 ≤ m ≤ 50,000,数值<=2^31-1。

 

解法是,先把所有数字从小到大排序,相同的按出现的先后顺序排序。

更新时,对于每一个数x,如果前面的y==x的话,那么在线段树中,在x的坐标位置上赋值上y的坐标位置。

查询时,[a,b]就是查询区间[a,b]中大于等于a的最大值。如果最大值都小于a,那么就说明没有重复的。

 

比如上面的数据1 2 3 1 2,排序后就是:

        1  1  2  2  3

pos:1  4  2  5  3

那么线段树中,[4,4]的值就是1,[5,5]的值就是2。其他线段没有值。

那么我们查询[1,4]的时候,显然最大值就是1,1大于等于[1,4]中的1,这就说明了有重复。因为线段[4,4]的值1实际上就说明了,原来在下标1到下标4有重复的数出现了。

还不清楚的话我们可以再试试查询区间[2,4],线段[2,4]在线段树上的最大值还是1,它小于2,没有重复。

这里说明了,[1,4]有重复的话,如果我们想要得到一个重复的区间,那么我们查询区间的左边界一定要小于等于1才有可能,这也是[2,4]没有重复区间的原因。

 

View Code
  1 #include<iostream>
  2 #include<string>
  3 #include<stdio.h>
  4 #include<memory.h>
  5 #include<algorithm>
  6 using namespace std;
  7 int max(int a,int b){return a>b?a:b;}
  8 
  9 struct node
 10 {
 11     int l;
 12     int r;
 13     int val;
 14 };
 15 
 16 struct Point
 17 {
 18     int pos;
 19     int val;
 20 };
 21 
 22 Point x[500001];
 23 int n;
 24 node tree[2500000];
 25 int X[500001];
 26 
 27 void build(int i,int l,int r)
 28 {
 29     tree[i].l=l;
 30     tree[i].r=r;
 31     tree[i].val=0;
 32     if(l==r)
 33         return;
 34     int mid=(l+r)/2;
 35     build(2*i,l,mid);
 36     build(2*i+1,mid+1,r);
 37 }
 38 
 39 void updata(int i,int l,int r,int w)
 40 {
 41     if(tree[i].l>r || tree[i].r<l)
 42         return;
 43     if(tree[i].l>=l && tree[i].r<=r)
 44     {
 45         tree[i].val=w;
 46         return;
 47     }
 48     updata(2*i,l,r,w);
 49     updata(2*i+1,l,r,w);
 50     tree[i].val=max(tree[2*i].val,tree[2*i+1].val);
 51 }
 52 
 53 int ans;
 54 void find(int i,int l,int r)
 55 {
 56     if(tree[i].l>r || tree[i].r<l)
 57         return;
 58     if(tree[i].l>=l && tree[i].r<=r)
 59     {
 60         ans=max(ans,tree[i].val);
 61         return;
 62     }
 63     find(2*i,l,r);
 64     find(2*i+1,l,r);
 65 }
 66 
 67 int cmp(Point a,Point b)
 68 {
 69     if(a.val!=b.val)
 70         return a.val<b.val;
 71     else
 72         return a.pos<b.pos;
 73 }
 74 
 75 int main()
 76 {
 77     int i,a,b,m;
 78     freopen("D:\\in.txt","r",stdin);
 79     while(scanf("%d",&n)==1)
 80     {
 81         for(i=0;i<n;i++)
 82         {
 83             scanf("%d",&x[i].val);
 84             X[i+1]=x[i].val; //保护原始数据的顺序
 85             x[i].pos=i+1;
 86         }
 87         build(1,1,n);
 88         sort(x,x+n,cmp);
 89         for(i=1;i<n;i++)
 90         {
 91             if(x[i].val==x[i-1].val)
 92             {
 93                 updata(1,x[i].pos,x[i].pos,x[i-1].pos);
 94             }
 95         }
 96         scanf("%d",&m);
 97         while(m--)
 98         {
 99             scanf("%d%d",&a,&b);
100             ans=0;
101             find(1,a,b);
102             if(ans<a)
103                 printf("OK\n");
104             else
105                 printf("%d\n",X[ans]);
106         }
107         printf("\n");
108     }
109     return 0;
110 }

 

 

 

posted @ 2012-08-26 20:09  Accept  阅读(544)  评论(0编辑  收藏  举报