洛谷P1908求逆序对【树状数组】

逆序对的定义:对于给定的一段正整数序列,逆序对就是序列中 ai>aj,i<ja_i>a_j,i<j,让统计逆序对的个数。

本题的数据加强,允许存在重复的数字。这并不影响下面分析的正确性。
思路
对于a[ i ] ,我们要求的是它前面大于a [ i ]的个数。
采用的思路是: i减去 小于等于a[i]的个数,剩下的就是大于a[i] 的个数

使用树状数组来求前缀和(query),也就是来计算小于等于a[i]的个数,对于第i个数a[ i ],其逆序对的个数是i-query(a[i])

我是看了这篇博客会的https://blog.csdn.net/ssimple_y/article/details/53744096
这里需要注意的是位置的理解,即a数组中的数值a[i],作为另一个数组中的下标。 t[a[i]]t[a[i] ]
比如 数组a={5,2,3,4,1},假设数组下标是1~5,a[1]==5,5就是在数组 t 中的下标,5出现一次5的位置就加1,t数组初始化全0.

遍历a数组
a[1]=5,数组t中t[a[1]]=t[5]1t[a[1]] = t[5]加1;
在这里插入图片描述
这个时候对数组t求前缀和(从第一项加到t[5]),sum=1,意思是在前面包括自身,≤5的个数=1,此时i=1,表示总共一个数,则其中大于5的个数=0;

遍历到a[2]=2,数组t中t[a[2]]=t[2]1t[a[2]] = t[2]加1;
在这里插入图片描述
此时对数组t关于t[2] 求前缀和,发现等于1,意思是a数组2前面包括2本身有1个数字≤2。此时i=2,总共有2个数,其中比2大的个数:2-1=1。也就是逆序的个数。
逆序对个数 ans+=i-前缀和(a[i]).
此时逆序对个数:ans=1;
遍历到a[3]=3
在这里插入图片描述发现t[3]前面的前缀和=2,意思是3前面包括本身≤3的个数是2,此时i=3,总共三个数,前面比3大的个数是:3-2=1;
此时逆序对个数 ans+=1 ,所以 ans=2;

遍历到a[4]=4,
在这里插入图片描述

发现t[4]前面的前缀和=3,意思是4前面有3个数小于等于4。换句话说,有1个大于4,所以逆序对个数 加1
逆序对个数:ans+=1,所以 ans=3
遍历到a[5]=1,在这里插入图片描述

发现t[1]的前缀和为1,则1前面比1小的数的个数为1.此时i=5,5-1=4为逆序对的个数

所以逆序对的个数 ans+=4;
最终ans=7;

ac代码

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
ll  n,a[maxn],b[maxn];//离散化用数组 
ll t[maxn];//树状数组 


//快读 
inline ll read(){
	ll k=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1;
		c=getchar();
	}
	
	while(c>='0'&&c<='9'){
		k=k*10+c-'0';
		c=getchar();
	}
	return f*k;
}

//计算前驱和后继 
ll lowbit(ll x){
	return x&-x;
}

// 树状数组更新 
void update(ll i,ll k){
	while(i<=n){
		t[i]+=k;
		i+=lowbit(i);
	}
	
}

//前缀和 
ll query(ll x){
	ll res=0;
	while(x>0){
		res+=t[x];
		x-=lowbit(x);
	}
	return res;
} 



int main(){
	
	n=read();
	for(ll i=1;i<=n;i++){
		a[i]=read();
		b[i]=a[i];
	}
	sort(b+1,b+n+1);
	ll m=unique(b+1,b+1+n)-b;
	for(ll i=1;i<=n;i++){
		a[i]=lower_bound(b+1,b+1+n,a[i])-b;//用来离散化
	}
	ll ans=0;
	for(ll i=1;i<=n;i++){
		update(a[i],1);//树状数更新,出现的话,给位置+1
		ans+=i-query(a[i]);//维护的是比a[i]大的个数,累加就是答案
	}
	printf("%lld",ans);
	
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章