链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3633
题意:给出一n个数的序列,然后又m个询问[x,y](下标),如果[x,y]内没有重复的数,就输出OK,否则输出从右至左第一个重复的数字
测试数据:
5 1 2 3 1 2 3 1 4 1 5 3 5[1,4]间从右到左第一个重复的数字是1
[1,5]是2
[3,5]之间没有重复的数字,输出OK
这个题可以用STL的map直接做,也可以用线段树做,这里介绍线段树的做法
此题叶子节点只能保存下标,如果数值不离散化的话肯定存不下(太大了,<2^31-1)
先将n个数排序,从小到大,相同的数按下标从小到大
如果有连续的两个数是相等的,那么在树中以后一个数为下标的节点的值更新为一个数的下标,以此类推,同时向上
更新区间的最大值(因为需要输出最右的那个重复数字)
查询下标[x,y]的时候,如果结果t>=x那么表明有重复的值,否则没有。原理就是要保证这个重复出现的数字向前最近的一个相等的数字在下标[x,y]内
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXN 500005
struct node
{
int l,r;
int s;
}t[MAXN*4];
struct ele
{
int e;
int idx;
}a[MAXN];
int b[MAXN];
int max(int a,int b)
{
return a>b?a:b;
}
void construct(int l,int r,int p)
{
t[p].l=l,t[p].r=r,t[p].s=0;
if(l==r) return ;
int m=(l+r)>>1;
construct(l,m,p*2);
construct(m+1,r,p*2+1);
}
void insert(int x,int p,int val)
{
if(t[p].l==t[p].r)
{
t[p].s=val;
return ;
}
int m=(t[p].l+t[p].r)>>1;
if(x<=m) insert(x,p*2,val);
else insert(x,p*2+1,val);
t[p].s=max(t[p*2].s,t[p*2+1].s);
}
int query(int l,int r,int p)
{
if(t[p].l==l&&t[p].r==r)
return t[p].s;
int m=(t[p].l+t[p].r)>>1;
if(r<=m) return query(l,r,p*2);
if(l>m) return query(l,r,p*2+1);
else return max(query(l,m,p*2),query(m+1,r,p*2+1));
}
int cmp(const void *a,const void *b)
{
if(((ele*)a)->e==((ele*)b)->e)
return ((ele*)a)->idx-((ele*)b)->idx;
return ((ele*)a)->e-((ele*)b)->e;
}
int main()
{
int n,m,i,x,y;
while(scanf("%d",&n)!=EOF)
{
construct(1,n,1);
for(i=1;i<=n;i++) scanf("%d",&a[i].e),a[i].idx=i,b[i]=a[i].e;
qsort(a+1,n,sizeof(ele),cmp);
for(i=2;i<=n;i++)
if(a[i].e==a[i-1].e)
insert(a[i].idx,1,a[i-1].idx);
scanf("%d",&m);
while(m--)
{
scanf("%d%d",&x,&y);
int t=query(x,y,1);
if(t>=x) printf("%d\n",b[t]);
else printf("OK\n");
}
printf("\n");
}
return 0;
}