[JOI Open 2025] 冒泡排序机 / Bubble Sort Machine
[JOI Open 2025] 冒泡排序机 / Bubble Sort Machine
考虑刻画冒泡排序的过程。
我们不妨手玩几个样例,比如对于序列 \([2,0,2,6,0,4,0,1]\),其进行冒泡排序的结果:
-
\(0\) 轮:\([2,0,2,6,0,4,0,1]\)。
-
\(1\) 轮:\([0,2,2,0,4,0,1,6]\)。
-
\(2\) 轮:\([0,2,0,2,0,1,4,6]\)。
-
\(3\) 轮:\([0,0,2,0,1,2,4,6]\)。
-
\(4\) 轮:\([0,0,0,1,2,2,4,6]\)。
后面的轮次都是 \([0,0,0,1,2,2,4,6]\)。
我们猜测经过 \(x\) 轮排序后的前 \(y\) 个数,是原序列的前 \(x+y\) 个数中前 \(y\) 小的。
结论根据冒泡排序的性质是显然的,具体考虑前 \(y\) 个数在一轮排序后会移除最大的一个。
将区间和转化为前缀和,问题变为求前缀前 \(k\) 小之和。
时空复杂度 \(O(n \log n)\)。
//Ad astra per aspera
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[500010],id[500010],num[500010];
bool cmp(const int &lhs,const int &rhs){
return a[lhs]<a[rhs];
}
int root[500010];
int lc[20000010],rc[20000010],sum_cnt[20000010],tot;
long long sum_num[20000010];
void pushup(int id){
sum_cnt[id]=sum_cnt[lc[id]]+sum_cnt[rc[id]];
sum_num[id]=sum_num[lc[id]]+sum_num[rc[id]];
}
void build_tree(int &id,int l,int r){
id=++tot;
if(l<r){
int mid=(l+r)>>1;
build_tree(lc[id],l,mid);
build_tree(rc[id],mid+1,r);
}
}
void add_tree(int id1,int &id2,int l,int r,int pos){
id2=++tot;
if(l==r){
sum_cnt[id2]=1;
sum_num[id2]=num[pos];
}
else{
int mid=(l+r)>>1;
if(pos<=mid){
rc[id2]=rc[id1];
add_tree(lc[id1],lc[id2],l,mid,pos);
}
else{
lc[id2]=lc[id1];
add_tree(rc[id1],rc[id2],mid+1,r,pos);
}
pushup(id2);
}
}
int n,q;
long long query(int id,int l,int r,int k){
if(l==r){
return sum_num[id];
}
int mid=(l+r)>>1;
if(sum_cnt[lc[id]]>=k){
return query(lc[id],l,mid,k);
}
else{
return sum_num[lc[id]]+query(rc[id],mid+1,r,k-sum_cnt[lc[id]]);
}
}
long long qry(int rnd,int id){
return query(root[min(n,id+rnd)],1,n,id);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
id[i]=i;
}
sort(id+1,id+n+1,cmp);
for(int i=1;i<=n;i++){
num[i]=a[id[i]];
a[id[i]]=i;
}
build_tree(root[0],1,n);
for(int i=1;i<=n;i++){
add_tree(root[i-1],root[i],1,n,a[i]);
}
scanf("%d",&q);
int pre_round=0;
while(q--){
int cmd;
scanf("%d",&cmd);
if(cmd==2){
int l,r;
scanf("%d %d",&l,&r);
long long ans=qry(pre_round,r);
if(l>1){
ans-=qry(pre_round,l-1);
}
printf("%lld\n",ans);
}
else{
pre_round++;
}
}
return 0;
}

浙公网安备 33010602011771号