区间询问,用莫队处理
记录每种颜色出现的次数,然后令 si s i 表示当前区间有多少种颜色出现次数在 (i−1)∗S+1∼i∗S ( i − 1 ) ∗ S + 1 ∼ i ∗ S 之间,这样就可以 O(nS+S) O ( n S + S ) 求出第 k k 大的出现次数是多少
令 用多少种编号在 (i−1)∗S+1∼i∗S ( i − 1 ) ∗ S + 1 ∼ i ∗ S 之间的颜色出现次数为 c c ,这样就可以 求出是那种颜色啦
S S 取 总复杂度是 O(nn−−√) O ( n n )
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=100010,M=320;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
int maxn,n,m,S,a[N],sum[N][M],b[N],ans[N],tot[M],cnt[N],ap[N];
struct Qry{
int l,r,k,g;
friend bool operator <(Qry x,Qry y){
return b[x.l]<b[y.l] || (b[x.l]==b[y.l] && (b[x.l]&1?x.r<y.r:x.r>y.r));
}
}Q[N];
inline void add(int x,int y){
cnt[ap[x]]--;
tot[b[ap[x]]]--;
sum[ap[x]][b[x]]--;
ap[x]+=y;
cnt[ap[x]]++;
tot[b[ap[x]]]++;
sum[ap[x]][b[x]]++;
}
inline int Query(int k){
if(n-cnt[0]<k) return 0;
int p;
for(p=maxn;p;p--)
if(tot[p]>=k) break; else k-=tot[p];
for(p=p*S;;p--)
if(cnt[p]>=k) break; else k-=cnt[p];
int *s=sum[p],q;
for(q=1;q<=maxn;q++)
if(s[q]>=k) break; else k-=s[q];
for(q=(q-1)*S+1;;q++)
if(ap[q]==p && !--k) break;
return q;
}
int main(){
read(n); S=sqrt(n);
for(int i=1;i<=n;i++)
read(a[i]),b[i]=(i-1)/S+1; maxn=b[n];
read(m);
for(int i=1;i<=m;i++)
read(Q[i].l),read(Q[i].r),read(Q[i].k),Q[i].g=i;
sort(Q+1,Q+1+m); cnt[0]=n;
int L=1,R=0;
for(int i=1;i<=m;i++){
while(R<Q[i].r) add(a[++R],1);
while(R>Q[i].r) add(a[R--],-1);
while(L>Q[i].l) add(a[--L],1);
while(L<Q[i].l) add(a[L++],-1);
ans[Q[i].g]=Query(Q[i].k);
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}