BZOJ3295 CQOI2011 動態逆序對
3295: [Cqoi2011]動態逆序對
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2263 Solved: 721
[Submit][Status][Discuss]
Description
對於序列A,它的逆序對數定義為滿足i<j,且Ai>Aj的數對(i,j)的個數。給1到n的一個排列,按照某種順序依次刪除m個元素,你的任務是在每次刪除一個元素之前統計整個序列的逆序對數。Input
輸入第一行包含兩個整數nOutput
輸出包含m行,依次為刪除每個元素之前,逆序對的個數。Sample Input
5 41
5
3
4
2
5
1
4
2
Sample Output
52
2
1
樣例解釋
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
HINT
N<=100000 M<=50000
這道題顯然是裸題,不過即使是裸題還是有一點點價值的,因為這種題的做法比較多,可以多練習下模板(捂臉)。
做法1:主席樹,這個很顯然,不用多說了,PS:因為M是N的一半,所以要靜態建樹,修改M次時再套用樹狀陣列,空間複雜度是MlogNlogN,否則是NlogNlogN,會爆空間(不要問我為什麼知道,我不想說=.=)
做法2:二維線段樹,和主席樹差不多啊,同樣要注意空間問題。
做法3:樹狀陣列套平衡樹。如果平衡樹選擇的是Splay就要注意很多問題:同樣要先靜態求出答案,因為splay的常數比較大,同時插入的時候要打亂順序,因為Splay若是插入有序的數列複雜度會退化(話說是不是我寫的不對?)。所以比較好的選擇是用Treap,常數很低,複雜度穩定,直接倒過來插入N個數就行了,簡單粗暴,程式碼100行都不要(主席樹和Splay的我寫了150行)。
做法4:分塊,這個程式碼就更短了,不過複雜度堪憂,Nsqrt(N)log(sqrt(N)),不過令人高興的是BZOJ貌似是隻看總時間的(?),所以可以水過,PS:分塊的總時間看來並沒有比前面幾種演算法慢,是資料水還是複雜度可以特殊分析?
做法5:顯然後面的插入對前面的詢問不會有影響,且這個問題的本質是計數問題,所以插入之間互相不影響效果,即每個插入對答案的貢獻是獨立的,所以我們可以採用按時間分治的演算法,將操作(一個點的插入和詢問可以分成兩個)分成兩部分,遞迴處理後再計算前半部分的插入對後半部分的查詢造成的影響。那麼我們將原問題轉化為:
給定平面上一些點,再詢問若干個點,回答詢問的點左上角(右下角的可以分開來做,也可以合起來)(即座標在他之前的,值比他大)有多少個點。那麼我們此時將詢問和給定點再看成一些操作並按X座標排序,我們發現該問題仍然滿足之前的性質,即X座標大的插入不影響X座標小的詢問,那麼我們再次運用按時間分治,將問題繼續簡化為:
給定一些數和一些詢問數,對於每個詢問回答比他大的數有多少個。顯然若將詢問和插入排好序,則可以線性回答,我們發現在分治時已經將該區間的左右分別排序,那麼怎麼得到這個區間的排序呢?這個問題是不是很熟悉,對!就是歸併排序,同時歸併排序的本質也就是按時間分治。
那麼處理最後一個問題的複雜度就是O(N),同時我們套用了兩層分治,總複雜度為NlogNlogN,由於分治的常數特別小,而且空間佔用為O(N),所以該做法的空間,時間,程式設計複雜度均小於前面幾種做法。(CDQ大法好,離線大法好)
至於程式碼呢,我當然是沒有的,畢竟我這種人只會耍嘴炮=.=(這種模板題放了程式碼也沒用吧,自己寫一遍最好理解)