CF840D 题解
题意解析
区间查询最小的数字,使得该数字出现次数严格大于
做法介绍
首先有一个关键的洞察,就是给整个区间排序后相同元素连续段必有一段长度超过阈值,而阈值
主席树当然可以做,但是常数稍大。针对这种二维数点问题,另一种比较好的做法是小波矩阵。小波矩阵的思想就是逐位划分整个数组,常数非常小。
具体原理参见:小波矩阵模板题题解。
代码编写
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
const int N=3e5+10;
const int Inf=0x3f3f3f3f;
const int W=20;
struct Vect{
ull msk[(N>>6)+3];
int cnt[(N>>6)+3];
int tot=0;
int n;
Vect(int l=N){
n=l;
memset(msk,0,sizeof(msk));
memset(cnt,0,sizeof(cnt));
}
inline void set(int k,ull bit){
msk[k>>6] |= bit << (k&63);
tot+=bit;
}
inline void build(){
for(int i=0;(i<<6)<n;i++){
cnt[i+1]=cnt[i]+__builtin_popcountll(msk[i]);
}
}
inline int query(int k){
return cnt[k>>6] + __builtin_popcountll(msk[k>>6] & (1ull<<(k&63))-1);
}
};
struct Wavelet_Matrix{
Vect m[W];
vector<int> tmp;
int n;
void init(int l,int *a){
n=l;
tmp.resize(n+3);
int t=0;
for(int j=0;j<W;j++) m[j].n=n;
for(int i=1;i<=n;i++) tmp[i]=a[i];
for(int j=W-1;j>=0;j--){
t=0;
for(int i=1;i<=n;i++) a[i]=tmp[i];
for(int i=1;i<=n;i++) m[j].set(i,a[i]>>j&1);
m[j].build();
for(int i=1;i<=n;i++) if(a[i]>>j&1^1) tmp[++t]=a[i];
for(int i=1;i<=n;i++) if(a[i]>>j&1) tmp[++t]=a[i];
}
return;
}
int query_kth(int l,int r,int k){
for(int i=W-1;i>=0;i--){
int tot=n-m[i].tot;
int cl=m[i].query(l),cr=m[i].query(r+1);
int cnt=(r-l+1)-(cr-cl);
if(k>cnt){
k-=cnt;
l=tot+cl+1;
r=tot+cr;
}else{
l-=cl;
r-=cr;
}
}
return tmp[l];
}
int query_cnt(int l,int r,int x){
for(int i=W-1;i>=0 && l<=r;i--){
int tot=n-m[i].tot;
int cl=m[i].query(l),cr=m[i].query(r+1);
if(x>>i&1){
l=tot+cl+1;
r=tot+cr;
}else{
l-=cl;
r-=cr;
}
}
return max(0,r-l+1);
}
}matrix;
int a[N];
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n,q;
cin>>n>>q;
for(int i=1;i<=n;i++) cin>>a[i];
matrix.init(n,a);
for(int i=1;i<=q;i++){
int l,r,k,ans=Inf;
cin>>l>>r>>k;
int t=(r-l+1)/k;
for(int i=t+1;i<=(r-l+1);i+=(t+1)){
int x=matrix.query_kth(l,r,i);
if(matrix.query_cnt(l,r,x)>t) ans=min(ans,x);
}
cout<<(ans>n?-1:ans)<<'\n';
}
}