题目大意
解题思路
较简单的一道主席树题
每次询问时,先处理处当前的区间,然后在主席树上二分
设当前二分区间为
[
l
,
r
]
[l,r]
[l,r],且满足要求的最少出现次数为
k
k
k(
k
=
⌊
r
−
l
+
1
2
⌋
+
1
k=\lfloor \frac{r-l+1}{2} \rfloor +1
k=⌊2r−l+1⌋+1)。
- 如果 [ l , r ] [l,r] [l,r] 左右两半的值都小于 k k k:直接退出并输出 0 0 0
- 否则,左右两半中一定有且仅有一半的值大于等于 k k k:找到那一半并继续二分
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int Maxn=500000+10,Maxm=11000000+10;
int sum[Maxm],ls[Maxm],rs[Maxm];
int a[Maxn],root[Maxn];
int n,m,idcnt;
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
void modify(int &x,int y,int l,int r,int pos)
{
x=++idcnt;
ls[x]=ls[y];
rs[x]=rs[y];
sum[x]=sum[y]+1;
if(l==r)return;
int mid=(l+r)>>1;
if(pos<=mid)modify(ls[x],ls[y],l,mid,pos);
else modify(rs[x],rs[y],mid+1,r,pos);
}
int query(int x,int y,int l,int r,int v)
{
if(sum[x]-sum[y]<v)return 0;
if(l==r)return l;
int mid=(l+r)>>1,ret=0;
ret=query(ls[x],ls[y],l,mid,v);
ret=max(ret,query(rs[x],rs[y],mid+1,r,v));
return ret;
}
int main()
{
// freopen("in.txt","r",stdin);
n=read(),m=read();
for(int i=1;i<=n;++i)
a[i]=read();
for(int i=1;i<=n;++i)
modify(root[i],root[i-1],1,n,a[i]);
while(m--)
{
int x=read(),y=read();
int ans=query(root[y],root[x-1],1,n,((y-x+1)>>1)+1);
printf("%d\n",ans);
}
return 0;
}