[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]-ksum_{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
",query(x));
	}
}

原文地址:https://www.cnblogs.com/birchtree/p/12562619.html