[NOI Online 提高组]冒泡排序(树状数组)
[NOI Online 提高组]冒泡排序(树状数组)
题面
略
分析
记\(f_i=\sum_{j=0}^i[a_j>a_i]\)表示\([1,i-1]\)中比\(a_i\)大的数的个数。那么逆序对数就是\(\sum_{i=1}^n f_i\).可以用树状数组预处理得出。
手玩一下冒泡排序过程发现,每冒泡一轮,所有的\(f_i\)会-1(减到0为止),然后会向前移动一位,即\(f_{i-1} \leftarrow f_i-1\).
那么冒泡\(k\)轮之后,\(f_1,f_2,\dots f_k\)会消失,所有\(\leq k\)的\(f_i\)会变为0。 注意到对于\(i \in [1,k]\),\(f_i < k\).因此这些数都会减为0,那么我们就不需要考虑平移,只需要考虑统计大于\(k\)的数,也就是说,\(f_i\)的位置没有意义.(比赛时没想到这一点,硬上一个树套树被卡成暴力分)
那么答案就是:
\[\sum_{i=1}^n f_i[f_i>k]-k\sum_{i=1}^n[f_i>k]
\]
因此我们要统计出\(>k\)的\(f_i\)的值之和,以及它们的个数。可以用两个树状数组实现。由于\(f_i<n\),我们可以把每个\(f_i\)的值存储在树状数组的第\(f_i\)位,查询时区间求和即可。
最后考虑修改。修改的时候只会改变\(f_x\)和\(f_{x+1}\)的值,若\(a_x>a_{x+1}\),则交换后比\(a_{x+1}\)小的数少了一个,那么\(f_{x+1}\)-1.反之\(f_x\)+1,然后交换\(f_x,f_{x+1}\). 可以用树状数组单点修改实现
代码
#include<iostream>
#include<cstdio>
#include<utility>
#include<cstring>
#define maxn 200000
using namespace std;
typedef long long ll;
int n,m,a[maxn+5],f[maxn+5];
struct fenwick_tree{
ll c[maxn+5];
inline int lowbit(int x){
return x&-x;
}
void ini(){
for(int i=1;i<=n;i++) c[i]=0;
}
void add(int x,int v){
if(x==0) return;
for(int i=x;i<=n;i+=lowbit(i)) c[i]+=v;
}
ll sum(int x){
ll ans=0;
for(int i=x;i>0;i-=lowbit(i)) ans+=c[i];
return ans;
}
ll query(int l,int r){
return sum(r)-sum(l-1);
}
}T1,T2,T3;
void insert_f(int val){
T2.add(val,1);
T3.add(val,val);
}
void del_f(int val){
T2.add(val,-1);
T3.add(val,-val);
}
pair<ll,ll>query_f(int l,int r){
return make_pair(T2.query(l,r),T3.query(l,r));
}
void change(int x){
del_f(f[x]);
del_f(f[x+1]);//先把原来的去掉
if(a[x]<a[x+1]) f[x]++;
else f[x+1]--;
swap(f[x],f[x+1]);
swap(a[x],a[x+1]);
insert_f(f[x]);
insert_f(f[x+1]);
}
ll query(int k){
if(k>=n) return 0;
pair<ll,ll>tmp=query_f(k+1,n);
//对于位置在k之前的,逆序对数一定<k,所以会被减成0
//我们只需要算所有值>k的即可,不需要考虑位置
return tmp.second-tmp.first*k;
}
int main(){
int cmd,x;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
f[i]=i-1-T1.sum(a[i]);
T1.add(a[i],1);
}
for(int i=1;i<=n;i++) insert_f(f[i]);
for(int i=1;i<=m;i++){
scanf("%d %d",&cmd,&x);
if(cmd==1) change(x);
else printf("%lld\n",query(x));
}
}
版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢