洛谷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);
	
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章