POJ 2299 Ultra-QuickSort(树状数组+离散化)
題目大意:
就是說,給你一個序列,然后讓你求出這個序列有多少個逆序對,所謂逆序對就是對于這個序列中的元素有a[i]>a[j] 且i<j存在。
其實原題是這樣說的,給你一個序列,讓你用最少的交換次數使得這個序列變成從小到大的排序.
解題思路:
一開始是想到了歸并的思路,但是沒有能寫出來代碼.
先來來范圍吧,序列的長度n<=500000+4. ? 并且每個a[i]<=999 999 999,對于tree[i],我們知道這個數組肯定是放不下的,所以
我們要進行離散化的處理,關于離散化的處理,我今天才剛剛看課件學會,,,
先來談談什么是離散化吧。
離散化就是說,我現在有一個數組,這個數組中的某些元素值大的或者小的可怕,但是,我所進行的詢問和序列中某個元素的值都是無關的,
那么,我們就可以利用離散化來處理,就是說,對于以前的這個數組,在某種不改變原先序列的大小關系的情況下的映射。
?舉個例子: –原數組ax [-1, 120, 13, 45, 12, 12] –排序去重后得到[-1, 12, 13, 45, 120] –映射完后得到新的ax數組 [1,5,3,4,2,2] ?一種比較簡單的寫法: –將所有操作到的數用一個數組存起來,然后排序,去重,該數在數組中的下標就是映射后的新的編號。
1 void discrete() 2 { 3 memset(data,0,sizeof(data)); 4 for ( int i = 0;i < n;i++ ) 5 { 6 data[i] = a[i]; 7 } 8 sort(data,data+n); 9 int cc = unique(data,data+n)-data; 10 for ( int i = 0;i < n;i++ ) 11 { 12 a[i] = 1+lower_bound(data,data+cc,a[i])-data; 13 } 14 }
?
現在來討論下,如何利用BIT來求解逆序數呢?
3. 離散之后,怎么使用離散后的結果數組來進行樹狀數組操作,計算出逆序數?
??? 如果數據不是很大, 可以一個個插入到樹狀數組中,
??? 每插入一個數, 統計比他小的數的個數,
??? 對應的逆序為 i- read(a[i]),
??? 其中 i 為當前已經插入的數的個數,也就是插入的這個數字的下標了.
??? read(a[i])為比 a[i] 小的數的個數,
??? i- read( a[i] ) 即比 a[i] 大的個數, 即逆序的個數
??? 但如果數據比較大,就必須采用離散化方法
??? 假設輸入的數組是9 1 0 5 4, 離散后的結果aa[] = {5,2,1,4,3};
在離散結果中間結果的基礎上,那么其計算逆序數的過程是這么一個過程。
1,輸入5,?? 調用update(5, 1),把第5位設置為1
1 2 3 4 5
0 0 0 0 1
計算1-5上比5小的數字存在么? 這里用到了樹狀數組的read(5) = 1操作,
現在用輸入的下標1 - read(5) = 0 就可以得到對于5的逆序數為0。
2. 輸入2, 調用update(2, 1),把第2位設置為1
1 2 3 4 5
0 1 0 0 1
計算1-2上比2小的數字存在么? 這里用到了樹狀數組的read(2) = 1操作,
現在用輸入的下標2 - read(2) = 1 就可以得到對于2的逆序數為1。
3. 輸入1, 調用update(1, 1),把第1位設置為1
1 2 3 4 5
1 1 0 0 1
計算1-1上比1小的數字存在么? 這里用到了樹狀數組的read(1) = 1操作,
現在用輸入的下標 3 - read(1) = 2 就可以得到對于1的逆序數為2。
4. 輸入4, 調用update(4, 1),把第5位設置為1
1 2 3 4 5
1 1 0 1 1
計算1-4上比4小的數字存在么? 這里用到了樹狀數組的read(4) = 3操作,
現在用輸入的下標4 - read(4) = 1 就可以得到對于4的逆序數為1。
5. 輸入3, 調用update(3, 1),把第3位設置為1
1 2 3 4 5
1 1 1 1 1
計算1-3上比3小的數字存在么? 這里用到了樹狀數組read(3) = 3操作,
現在用輸入的下標5 - read(3) = 2 就可以得到對于3的逆序數為2。
6. 0+1+2+1+2 = 6 這就是最后的逆序數
分析一下時間復雜度,首先用到快速排序,時間復雜度為O(NlogN),
后面是循環插入每一個數字,每次插入一個數字,分別調用一次update()和read()
外循環N, update()和read()時間O(logN) => 時間復雜度還是O(NlogN).
最后總的還是O(NlogN).
?
?
代碼:
1 # include<iostream> 2 # include<cstdio> 3 # include<algorithm> 4 # include<cstring> 5 6 using namespace std; 7 8 # define MAX 500000+4 9 10 typedef long long LL; 11 12 LL a[MAX]; 13 LL data[MAX]; 14 int tree[MAX]; 15 int n; 16 17 void discrete() 18 { 19 memset(data,0,sizeof(data)); 20 for ( int i = 0;i < n;i++ ) 21 { 22 data[i] = a[i]; 23 } 24 sort(data,data+n); 25 int cc = unique(data,data+n)-data; 26 for ( int i = 0;i < n;i++ ) 27 { 28 a[i] = 1+lower_bound(data,data+cc,a[i])-data; 29 } 30 } 31 32 33 void update ( int pos,int val ) 34 { 35 while ( pos <= n ) 36 { 37 tree[pos]+=val; 38 pos += pos&(-pos); 39 } 40 } 41 42 int read ( int pos ) 43 { 44 int sum = 0; 45 while ( pos>0 ) 46 { 47 sum+=tree[pos]; 48 pos-=pos&(-pos); 49 } 50 return sum; 51 } 52 53 54 int main(void) 55 { 56 while ( cin>>n ) 57 { 58 if ( n==0 ) 59 break; 60 LL ans = 0; 61 for ( int i = 0;i < n;i++ ) 62 { 63 cin>>a[i]; 64 } 65 discrete(); 66 memset(tree,0,sizeof(tree)); 67 for ( int i = 0;i < n;i++ ) 68 { 69 update(a[i],1); 70 ans+=(i+1)-read(a[i]); 71 } 72 cout<<ans<<endl; 73 } 74 75 return 0; 76 }?
轉載于:https://www.cnblogs.com/wikioibai/p/4457176.html
總結
以上是生活随笔為你收集整理的POJ 2299 Ultra-QuickSort(树状数组+离散化)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js 乘法除法精度问题
- 下一篇: 基于http协议的api接口对于客户端的