乙個序列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 ...