题目链接:#6273. 郁金香
题目大意:给定一个长度为 (n) 序列 ({a_i}_{i=1}^{n}) , (m) 次询问区间 ([l,r]) 中出现次数第 (k) 多的数,如出现次数相同,则令数较小出现次数较多。
(n,m,a_ileq 10^5)
题解:听说有划分树的 ( ext{polylog}) 做法,可惜我并不会。<-- 不要听博主这个弱智的话,这问题严格强于区间众数。
直接莫队,令块长为 (S) ,那么我们考虑将值域分块,这样的话可以在 (O(S+frac{n}{S})) 的时间内求出出现次数。
接下来考虑求出现次数为 (x) 的第 (k) 小值,所以我们直接对序列分块,令 (f_{i,j}) 表示出现次数为 (i) 的数在第 (j) 块中的个数,容易发现可以在 (O(S+frac{n}{S})) 的时间内解决。
取 (S=sqrt{n}) 时最优,时间复杂度为 (O(qsqrt{n})) 。
代码:
#include <cstdio>
#include <algorithm>
using namespace std;
const int Maxv=100000;
const int Maxn=100000;
const int Maxs=334;
const int Maxb=(Maxn-1)/Maxs+1;
int n,m;
struct Question{
int l,r,k;
int id;
friend bool operator <(Question a,Question b){
if((a.l-1)/Maxs==(b.l-1)/Maxs){
if(((a.l-1)/Maxs)&1){
return a.r>b.r;
}
return a.r<b.r;
}
return a.l<b.l;
}
}qu[Maxn+5];
int a[Maxn+5];
int f[Maxv+5][Maxb+5];
int cnt[Maxn+5];
int sum[Maxn+5],s_block[Maxb+5];
int ans[Maxn+5];
void add(int x,int a){
int last=cnt[x];
cnt[x]+=a;
f[last][(x-1)/Maxs+1]--;
f[cnt[x]][(x-1)/Maxs+1]++;
if(last){
s_block[(last-1)/Maxs+1]--;
}
else{
s_block[0]--;
}
if(cnt[x]){
s_block[(cnt[x]-1)/Maxs+1]++;
}
else{
s_block[0]++;
}
sum[last]--;
sum[cnt[x]]++;
}
int query(int k){
int bel;
for(bel=(n-1)/Maxs+1;k>s_block[bel]&&bel;bel--){
k-=s_block[bel];
}
int num;
for(num=min(n,bel*Maxs);k>sum[num];num--){
k-=sum[num];
}
for(bel=1;k>f[num][bel];bel++){
k-=f[num][bel];
}
int pos;
for(pos=(bel-1)*Maxs+1;k>(cnt[pos]==num);pos++){
k-=(cnt[pos]==num);
}
return pos;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
scanf("%d",&m);
sum[0]=s_block[0]=n;
for(int i=1;i<=n;i++){
f[0][(a[i]-1)/Maxs+1]++;
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&qu[i].l,&qu[i].r,&qu[i].k);
qu[i].id=i;
}
sort(qu+1,qu+1+m);
int pos_l=1,pos_r=0;
for(int i=1;i<=m;i++){
if(qu[i].k>n){
ans[qu[i].id]=-1;
continue;
}
while(pos_r<qu[i].r){
pos_r++;
add(a[pos_r],1);
}
while(pos_l>qu[i].l){
pos_l--;
add(a[pos_l],1);
}
while(pos_r>qu[i].r){
add(a[pos_r],-1);
pos_r--;
}
while(pos_l<qu[i].l){
add(a[pos_l],-1);
pos_l++;
}
ans[qu[i].id]=query(qu[i].k);
if(cnt[ans[qu[i].id]]==0){
ans[qu[i].id]=-1;
}
}
for(int i=1;i<=m;i++){
if(ans[i]==-1){
puts("0");
}
else{
printf("%d
",ans[i]);
}
}
return 0;
}