1 条题解
-
0
本题
伟大的 carotrl 在 AH 省集中提出冒泡排序若干轮之后的结果是可以直接刻画的。
具体来说说前缀 在经过 轮冒泡排序之后的数字构成是原先区间 中的前 小的数,这个很好理解,经过 轮冒泡排序之后,某个数最多往前平移的位置数就是 ,所以范围是 ,而小的数会往前走,所以就是前 小。
这样子就可以完成本题了,我们直接拿 经过 轮冒泡排序之后的数字组成减去 的即可。区间 kth 信息可以直接拿主席树在线维护。时间复杂度 。
扩展版-区间前 小之和
改为若干次操作之后区间 的前 小值,如何做?
将上述定理扩展一些,前缀 经过冒泡排序 轮之后的前 小值为原序列中区间 的前 小值。
区间 经过 轮冒泡排序之后的前 小值就是前缀 中去除前缀 中的前 小值之后的前 小值,注意这里不能单纯拿两个作差,需要巧妙实现。
还是可以通过主席树在线维护的。本质还是对于两个前缀进行差分,需要设置一个阈值,意思是 这个区间最多贡献 。具体可以看看代码。
调用
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; }
- 1
信息
- ID
- 9593
- 时间
- 2000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者