主席树维护前缀信息(区间出现数的个数),通过两颗树相减,可以得到区间的信息。
询问的时候严格大于区间长度则大于(r - l + 1)/ 2,
- 如果左边出现点的个数大于这个,那么可能出现在左边
- 如果右边出现点的个数大于这个,那么可能出现在右边
- 否则为0,没有
代码
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int n,m;
int a[N],rt[N];
#define l(x) t[x].l
#define r(x) t[x].r
#define sum(x) t[x].sum
struct LSegmentTree{
int l,r,sum,val;
}t[N << 5];
int idx = 0;
int build(int l,int r){
int root = ++idx;
if(l == r) return root;
int mid = (l + r) >> 1;
l(root) = build(l,mid);
r(root) = build(mid+1,r);
return root;
}
int update(int p,int l,int r,int k){
int root = ++idx;
l(root) = l(p),r(root) = r(p),sum(root) = sum(p) + 1;
if(l == r) return root;
int mid = (l + r) >> 1;
if(k <= mid) l(root) = update(l(p),l,mid,k);
else r(root) = update(r(p),mid+1,r,k);
return root;
}
int query(int lp,int rp,int l,int r,int len){
if(l == r) return l;
int mid = (l + r) >> 1;
if(sum(l(rp)) - sum(l(lp)) > len) return query(l(lp),l(rp),l,mid,len);
if(sum(r(rp)) - sum(r(lp)) > len) return query(r(lp),r(rp),mid+1,r,len);
return 0;
}
signed main(){
IOS
int n,m; cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
rt[0] = build(1,n);
for(int i=1;i<=n;i++) rt[i] = update(rt[i-1],1,n,a[i]);
while(m --){
int l,r; cin>>l>>r;
cout<<query(rt[l-1],rt[r],1,n,(r - l + 1) / 2)<<endl;
}
return 0;
}