#6273. 郁金香 题解
题目链接:#6273. 郁金香
题目大意:给定一个长度为 \(n\) 序列 \(\{a_i\}_{i=1}^{n}\) , \(m\) 次询问区间 \([l,r]\) 中出现次数第 \(k\) 多的数,如出现次数相同,则令数较小出现次数较多。
\(n,m,a_i\leq 10^5\)
题解:听说有划分树的 \(\text{polylog}\) 做法,可惜我并不会。<-- 不要听博主这个弱智的话,这问题严格强于区间众数。
直接莫队,令块长为 \(S\) ,那么我们考虑将值域分块,这样的话可以在 \(O(S+\frac{n}{S})\) 的时间内求出出现次数。
接下来考虑求出现次数为 \(x\) 的第 \(k\) 小值,所以我们直接对序列分块,令 \(f_{i,j}\) 表示出现次数为 \(i\) 的数在第 \(j\) 块中的个数,容易发现可以在 \(O(S+\frac{n}{S})\) 的时间内解决。
取 \(S=\sqrt{n}\) 时最优,时间复杂度为 \(O(q\sqrt{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\n",ans[i]);
}
}
return 0;
}
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。