题解:P12865 [JOI Open 2025] 冒泡排序机 / Bubble Sort Machine
本题
伟大的 carotrl 在 AH 省集中提出冒泡排序若干轮之后的结果是可以直接刻画的。
具体来说说前缀
这样子就可以完成本题了,我们直接拿
扩展版-区间前 k 小之和
改为若干次操作之后区间
[l,r] 的前k 小值,如何做?
将上述定理扩展一些,前缀
区间
还是可以通过主席树在线维护的。本质还是对于两个前缀进行差分,需要设置一个阈值,意思是
调用 solve(rt[min(l+c-1,n)],rt[min(r+c,n)],1,n,l-1,k) 即可,其中
ll solve(int p,int q,int l,int r,int up,int cnt){
if(l==r) return 1ll*cnt*l;
int z=val[ls[q]]-min(val[ls[p]],up);
if(z>=cnt) return solve(ls[p],ls[q],l,mid,up,cnt);
int del=min(up,val[ls[p]]);
return sum[ls[q]]-query(0,ls[p],l,mid,del)+solve(rs[p],rs[q],mid+1,r,up-del,cnt-z);
}
Code
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb emplace_back
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
int a[maxn],b[maxn],rt[maxn],n,m,q;
inline int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
struct SegmentTree{
#define mid ((l+r)>>1)
int val[maxn<<6],ls[maxn<<6],rs[maxn<<6],tot; ll sum[maxn<<6];
void pushup(int p){ val[p]=val[ls[p]]+val[rs[p]]; sum[p]=sum[ls[p]]+sum[rs[p]]; }
void build(int &p,int q,int l,int r,int x){
p=++tot; ls[p]=ls[q]; rs[p]=rs[q];
val[p]=val[q]; sum[p]=sum[q];
if(l==r){ val[p]++; sum[p]+=b[x]; return ; }
if(x<=mid) build(ls[p],ls[q],l,mid,x);
else build(rs[p],rs[q],mid+1,r,x);
pushup(p);
}
ll query(int p,int q,int l,int r,int k){
if(l==r) return 1ll*k*b[l];
int z=val[ls[q]]-val[ls[p]];
if(z>=k) return query(ls[p],ls[q],l,mid,k);
else return sum[ls[q]]-sum[ls[p]]+query(rs[p],rs[q],mid+1,r,k-z);
}
}seg;
int main(){
cin>>n; int c=0;
for(int i=1;i<=n;i++) a[i]=read(),b[i]=a[i];
sort(b+1,b+1+n); m=unique(b+1,b+1+n)-(b+1); cin>>q;
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+m,a[i])-b;
for(int i=1;i<=n;i++) seg.build(rt[i],rt[i-1],1,m,a[i]);
for(int i=1;i<=q;i++){
int t,l,r; t=read();
if(t==1) c++;
else{
l=read(); r=read();
printf("%lld\n",seg.query(rt[0],rt[min(r+c,n)],1,m,r)-seg.query(rt[0],rt[min(l+c-1,n)],1,m,l-1));
}
}
return 0;
}