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 }

 

 

 

你可能感兴趣的:(线段树)