1. 程式人生 > 其它 >樹狀陣列優化暴力求逆序對

樹狀陣列優化暴力求逆序對

樹狀陣列優化暴力求逆序對

雖然說這個不難,但是為什麼大佬們的部落格都是一句話“用樹狀陣列的性質”然後就是程式碼了qwq,小蒟蒻愣是呆了半小時才明白。

離散化

3 -1 2 -2 這個數列有 5個逆序對

4 2 3 1 也是五個

我們把最小的-2視作1

第二的-1看做2

...

這樣就可以得到離散化後的陣列了,這個技巧可以用來去重去負數,可以在所有答案只與數字大小關係的情況下使用。

實現:結構體儲存陣列num 和它在原數組裡的下標

{3,1}{-1,2}{2,3}{-2,4}

然後按數字大小排序

{-2,4}{-1,2}{2,3}{3,1}

現在我們就得到了 4 2 3 1了。

樹狀陣列

a[]為原陣列

求逆序對,就是求在對於沒個i,a[1~i-1]中比a[i]大的數的個數的總和。

顯然一個簡單的處理方法就是每次讓b[a[i]]+1,然後找b[1~i-1]的和就代表在a[1~i-1]中比a[i]小的數的個數,一減就可以得到比a[i]大的個數。

再看一眼,這不就是求b[1~i-1]的區間和嗎,這裡就可以用到樹狀陣列了。(本人認為這個求逆序對的方法本質就是暴力,樹狀陣列無非是個優化,叫樹狀陣列逆序對屬實誤人子弟)

程式碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace
std; int tree[500010],rank[500010],n; long long ans; struct point { int num,val; }a[500010]; inline bool cmp(point q,point w) { if(q.val==w.val) return q.num<w.num; return q.val<w.val; } inline void insert(int p,int d) { for(;p<=n;p+=p&-p) tree[p]+=d; } inline int
query(int p) { int sum=0; for(;p;p-=p&-p) sum+=tree[p]; return sum; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i].val),a[i].num=i; sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++) rank[a[i].num]=i; for(int i=1;i<=n;i++) { insert(rank[i],1); ans+=i-query(rank[i]); } printf("%lld",ans); return 0; }