求逆序對(線段樹版)

2021-12-29 20:14:26 字數 1588 閱讀 2429

乙個序列a1,a2,a3...an,求出滿足:ai > aj 且 i < j 的個數。

乙個最容易想到的方法就是列舉所有的i,j看看是否滿足,顯然是o(n^2)的複雜度。不夠好。

可以這樣考慮,開乙個陣列儲存這n個數出現的位置和對應的次數,這個陣列要開到a陣列裡最大的那個數max,也就是hash,初始狀態陣列裡沒有元素,每個數對應的個數都是0.

如果考慮第i個數,找到比它大的所有的數 的個數,查詢的範圍即 ai+1~max,這就是到i這個位置的逆序對的總和,接著把a[i]這個數新增到陣列裡,也就是a[i]這個位置的數量加1。一直進行到n結束,逆序對就求了出來。

這樣做得複雜度依然是o(n^2),但查詢和增加的操作可用線段樹解決,這樣複雜度就降到了o(nlogn)。

還有乙個問題,如果a[i]可以達到10^9甚至更大,陣列都開不下,即便開的下,時間上也不能承受,這樣就要用到離散化,將n個數對映到1~n的範圍內,這個操作排序加二分可輕鬆解決。所有數控制在n 的範圍內,線段樹解決是非常理想的。

以poj2299為例 : 題目就是要求逆序對。詳見**:

#include

#include

#include

#include

#include

#include

#include

#include

#define lson o<<1, l, m

#define rson o<<1|1, m+1, r

using namespace std;

typedef long long ll;

const int maxn = 500500;

const int max = 0x3f3f3f3f;

int n, a, b, in[maxn], tt[maxn], fu[maxn], f[maxn];

ll num[maxn<<2];

int bs(int v, int x, int y)

return x;

}void up(int o)

void build(int o, int l, int r)

void update(int o, int l, int r)

int m = (l+r) >> 1;

if(a <= m) update(lson);

else update(rson);

up(o);

}ll query(int o, int l, int r)

int main()

sort(in, in+n);

int k = 0;

fu[k++] = in[0]; //fu為輔助陣列

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

if(in[i] != in[i-1]) fu[k++] = in[i];

b = 0;

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

ll ans = 0;

build(1, 0, b);

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

cout << ans << endl;

}return 0;

}

逆序對 線段樹解法

逆序對 線段樹解法 求逆序對問題是乙個十分經典的演算法問題,通常使用歸併排序解決,經gster大神指點,寫出了逆序對線段樹寫法,順便練了練線段樹。題目傳送門 1 2 segment tree 3author shhhs 42016 09 28 12 35 17 5 6 include bits st...

a703 求逆序對 線段樹的解法

time limit 10 second memory limit 2 mb 問題描述 給定乙個序列a1,a2.an。如果存在i小於j 並且ai大於aj,那麼我們稱之為逆序對,求給定序列中逆序對的數目 第一行為n,表示序列長度,接下來的n行,第i 1行表示序列中的第i個數。所有逆序對的總數 432 ...

a703 求逆序對 線段樹的解法

time limit 10 second memory limit 2 mb 問題描述 給定乙個序列a1,a2.an。如果存在i小於j 並且ai大於aj,那麼我們稱之為逆序對,求給定序列中逆序對的數目 第一行為n,表示序列長度,接下來的n行,第i 1行表示序列中的第i個數。所有逆序對的總數 432 ...