逆序對(樹狀陣列 歸併)

2021-07-26 06:53:55 字數 1382 閱讀 9023

題目描述

貓貓tom和小老鼠jerry最近又較量上了,但是畢竟都是成年人,他們已經不喜歡再玩那種你追我趕的遊戲,現在他們喜歡玩統計。最近,tom老貓查閱到乙個人類稱之為「逆序對」的東西,這東西是這樣定義的:對於給定的一段正整數序列,逆序對就是序列中i小於j同時ai大於aj的有序對。知道這概念後,他們就比賽誰先算出給定的一段正整數序列中逆序對的數目。

輸入輸出格式

輸入格式:

第一行,乙個數n,表示序列中有n個數。

第二行n個數,表示給定的序列。

輸出格式:

給定序列中逆序對的數目。

輸入輸出樣例

輸入樣例#1: 6

5 4 2 6 3 1

輸出樣例#1: 11

分析:不要在意題目為什麼這麼zz(從luogu上粘的。。。hh)

這個題的簡單思路是歸併,主體思路不變,但是在「並」的時候如果出現左邊子段中的元素大於右子段的元素這種情況,顯然右子段中的元素可以與剩下的左子段中的每乙個元素都組成逆序對。光這麼說應該是很難理解的,所以我們來舉個例子:

若當前情況如下:

a1 a2 a3 a4 a5 a6

2 4 5 1 6 7

i j(因為歸併是用遞迴實現的,所以可以保證左子端和右子段這單獨的兩部分是有序的)

看一下現在i和j所指的元素 a[i]=2,a[j]=1,此時a[i]>a[j],所以a[j]可以和左區間中從i到m(m=(左端點+右端點)/2)的每乙個元素組成逆序對,逆序對個數是:m-i+1

明白了原理之後,看**

#include#include#includeusing namespace std;

int a[40010],b[40010],n,ans=0;

int merge(int l,int r)

else

}for (k=l;k<=r;k++)

a[k]=b[k];

return 0;

}int sor(int l,int r)

;node ls[40010];

int com(const node &ha,const node &he)

int build(int x)

int main()

memset(c,0,sizeof(c));

sort(ls+1,ls+1+n,com); //下面是離散化操作,可能有點笨,見諒

int r=0,tot=0;

for (int i=1;i<=n;i++)

for (int i=n;i>=1;i--)

build(a[i]); //樹狀陣列的基本操作

printf("%d",ans);

return 0;

}

逆序對 (樹狀陣列 歸併排序

陣列前面的乙個元素 大於等於 後面的乙個元素就是乙個逆序對 樹狀陣列可以快速求字首和,利用這一特性,可以求逆序對個數,見下 用陣列c i 記錄陣列a n 中i這一元素出現的次數 當a n 中元素較大時可以離散化處理。將a n 從a n 1 到a 0 依次存到樹狀陣列中,每存乙個,對存的元素i求一次c...

求逆序對(歸併排序 樹狀陣列)

兩種演算法的時間複雜度都是 o nlogn 但是,有可能樹狀陣列需要離散化!所以,由許多元素共同影響下,歸併排序求逆序對 比 樹狀陣列求逆序對 歸併排序 include define ll long long define n 100005 using namespace std int a n t...

二路歸併 樹狀陣列 求解逆序對

常用的兩種方法,二路歸併 樹狀陣列。二路歸併求解逆序對 二路歸併是乙個十分完美的求逆序對的方法 假設當前求到這一步,現在比較a i a j 的大小,我們根據圖知道,i mid j,而且第一列有序 從小到大 第二列有序,當a i a j 說明a i 到a mid 都大於a j ans mid i 1。...