CF840D Destiny
Description
给定 \(k\leq 5\),求区间 \([l,r]\) 内出现次数严格大于 \(\frac{r-l+1}{k}\) 的最小的数,没有就输出 -1。
Solution
抓住区间总共只有 \(r-l+1\) 个数的特性,而 \(k\) 很小,那么出现次数很大的数一定不多,实际上严格小于 \(k\)。所以用主席树维护出现次数的和,如果某个值域的出现次数大于该阈值就递归下去。会发现每层被访问的节点不超过 \(k\) 个。那么单次询问复杂度就是 \(O(k\log n)\) 。
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
const int N=3e5+7;
struct Node{
int ls,rs,s;
}t[N*40];
#define lid t[id].ls
#define rid t[id].rs
int cnt=0,rt[N];
void build(int &id,int lf,int rf){
id=++cnt;
if(lf==rf) return ;
int mid=(lf+rf)>>1;
build(lid,lf,mid);
build(rid,mid+1,rf);
}
int Val;
void modify(int &id,int pre,int lf,int rf){
id=++cnt;
t[id]=t[pre]; t[id].s++;
if(lf==rf) return;
int mid=(lf+rf)>>1;
if(Val<=mid) modify(lid,t[pre].ls,lf,mid);
else modify(rid,t[pre].rs,mid+1,rf);
}
int query(int id,int pre,int lf,int rf){
if(lf==rf) return t[id].s-t[pre].s>=Val? lf:-1;
int mid=(lf+rf)>>1,ret=-1;
int s=t[lid].s-t[t[pre].ls].s;
if(s>=Val) ret=query(lid,t[pre].ls,lf,mid);
if(~ret) return ret;
s=t[rid].s-t[t[pre].rs].s;
return s>=Val? query(rid,t[pre].rs,mid+1,rf):-1;
}
int main(){
int n=read(),Q=read();
build(rt[0],1,n);
for(int i=1;i<=n;i++)
Val=read(),modify(rt[i],rt[i-1],1,n);
while(Q--){
int l=read(),r=read(),k=read();
Val=(r-l+1)/k+1,printf("%d\n",query(rt[r],rt[l-1],1,n));
}
}