题目链接
http://main.edu.pl/en/archive/oi/21/kur
题目大意
给定一个序列,对于每个询问 [Li,Ri] ,要在这个询问区间里找出一个数字,并且这个数字在这个区间中的出现次数要大于 [(Ri−Li+1)2] ,若无这个数字,则输出-1
思路
首先对于这个序列,建立一个静态的主席树,然后对于每次询问的区间,用前缀 Ri 和前缀 Li 的主席树做差,在得到的主席树里从根节点开始向下走,二分区间,即可找到这个数字
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 500010
using namespace std;
int n,m;
int root[MAXN],lc[MAXN*20],rc[MAXN*20],sum[MAXN*20];
int nCount=0;
void update(int last,int &o,int L,int R,int pos)
{
o=++nCount;
sum[o]=sum[last]+1;
if(L==R) return;
int M=(L+R)>>1;
lc[o]=lc[last],rc[o]=rc[last]; //!!!!!
if(pos<=M) update(lc[last],lc[o],L,M,pos);
else update(rc[last],rc[o],M+1,R,pos);
}
int query(int last,int o,int L,int R,int K)
{
if(sum[o]-sum[last]<=K) return 0;
if(L==R) return L;
int M=(L+R)>>1;
if(sum[lc[o]]-sum[lc[last]]>K)
return query(lc[last],lc[o],L,M,K);
else if(sum[rc[o]]-sum[rc[last]]>K)
return query(rc[last],rc[o],M+1,R,K);
else return 0;
}
/*
int query(int L,int R)
{
int l=1,r=n,mid,x,y,tmp=(R-L+1)>>1;
x=root[L-1];y=root[R];
while(l!=r)
{
if(sum[y]-sum[x]<=tmp)return 0;
mid=(l+r)>>1;
if(sum[lc[y]]-sum[lc[x]]>tmp)
{r=mid;x=lc[x];y=lc[y];}
else if(sum[rc[y]]-sum[rc[x]]>tmp)
{l=mid+1;x=rc[x];y=rc[y];}
else return 0;
}
return l;
}*/
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
update(root[i-1],root[i],1,n,x);
}
for(int i=1;i<=m;i++)
{
int L,R;
scanf("%d%d",&L,&R);
printf("%d\n",query(root[L-1],root[R],1,n,(R-L+1)>>1));
//printf("%d\n",query(L,R));
}
return 0;
}