设
p
=
r
−
l
+
1
k
+
1
p=\frac{r-l+1}{k}+1
p=kr−l+1+1,则如果一个权值出现了不小于p次,那我们将
[
l
,
r
]
[l,r]
[l,r]排序,这个权值一定在
p
,
2
p
.
.
.
,
k
p
p,2p...,kp
p,2p...,kp中的任意一个地方出现过
也就是说,我们找到这些位置上的数,再判断它们的出现次数是否小于p即可,用主席树可以方便实现
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=3e5+5;
int a[N],rt[N],cnt=0;
namespace President_tree{
struct seg{int sum,ls,rs;}tr[N*80];
#define lc(k) tr[k].ls
#define rc(k) tr[k].rs
void build(int &k,int l,int r){
k=++cnt;tr[k].sum=0;
if(l==r) return;
int mid=l+r>>1;
build(lc(k),l,mid);build(rc(k),mid+1,r);
}
void ins(int &k1,int k2,int l,int r,int v){
k1=++cnt;tr[k1]=tr[k2];++tr[k1].sum;
if(l==r) return;
int mid=l+r>>1;
if(v<=mid) ins(lc(k1),lc(k2),l,mid,v);
else ins(rc(k1),rc(k2),mid+1,r,v);
}
}
using namespace President_tree;
int main(){
int n=read(),q=read();
for(int i=1;i<=n;i++) a[i]=read();
build(rt[0],1,n);
for(int i=1;i<=n;i++) rt[i]=rt[i-1],ins(rt[i],rt[i],1,n,a[i]);
while(q--){
int l=read(),r=read(),k=read(),ans=-1;
int nw=(r-l+1)/k;
int L=1,R=n,k1=rt[r],k2=rt[l-1];
if(!nw){
while(L<R){
int mid=L+R>>1;
if(tr[lc(k1)].sum-tr[lc(k2)].sum>0) k1=lc(k1),k2=lc(k2),R=mid;
else k1=rc(k1),k2=rc(k2),L=mid+1;
}
cout<<L<<"\n";
}
else{
for(int i=nw;i<=r-l+1;i+=nw){
L=1,R=n,k1=rt[r],k2=rt[l-1];int now=i;
while(L<R){
int mid=L+R>>1,del=tr[lc(k1)].sum-tr[lc(k2)].sum;
if(del>=now) k1=lc(k1),k2=lc(k2),R=mid;
else k1=rc(k1),k2=rc(k2),L=mid+1,now-=del;
}
if((tr[k1].sum-tr[k2].sum)*k>r-l+1 && (L<ans || ans==-1)) ans=L;
}
cout<<ans<<"\n";
}
}
return 0;
}