淺談樹狀數組求逆序對


做了一道樹上求逆序對的題,主要難點並不在於樹形結構,而是求逆序對數。(在我看來是這樣的)。

to洛谷P3605晉升者計數。

發現自己樹狀數組求逆序對還有個坑,先填上再說。再加上最近學的樹狀數組離散化,捋一捋思路。

首先是離散化

for(int i=1;i<=n;i++){
	a[i].v=read();
    a[i].id=i;
}
sort(a+1,a+1+n);按v排序
for(int i=1;i<=n;i++)b[a[i].id]=i;

在上述代碼中,首先我們輸入的是a[i].v,也就是一開始的數據,我們將其放到結構體里,再記錄一下id,也就是原序。之后我們將a按照v排序,那么得到的就是從小到大的順序。

又因為離散化是為了避免數據太大而出鍋,所以我們在乎的就是數據的相對順序,所以很容易地想到,將他們的順序作為新的權值,這樣就可以保證相對大小不變並且還可以最大化的縮小數據范圍。

那么我們開一個新的數組,對應為離散化之后的數組,那么這個數組一定是要和原數組的順序相同的,所以這個時候原來記錄的id也就是原序就有了用場,然后再把當前這個元素的排名也就是i賦給離散化數組的第a[i].id位即可。

再來說逆序對數,在一個序列中,如果存在

\[i<j並且a[i]>a[j] \]

那么就代表有一個逆序對。

考慮如何用樹狀數組實現\(nlogn\)的時間復雜度求逆序對數。

首先,如果數據大我們需要離散化。

然后從1到n枚舉,考慮當前枚舉到的位置i,他對總的逆序對的個數的貢獻就是他前面的權值大於他的權值的數的個數,所以我們在i的權值的位置修改樹狀數組,表示i的權值這個數已經出現過了,那么到了后面就可以直接查詢從1到i的權值的位置的總和,因為1代表有,0代表沒有,所以返回的值即為從一到i小於等於他的權值的數有幾個,單步容斥即可得到大於他的數目也就是逆序對數。

code

for(int i=1;i<=n;i++){
	update(b[i],1);
    ans+=query(b[i]);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM