動態逆序對 CQOI2011

2022-05-11 16:07:03 字數 1417 閱讀 1545

更好的閱讀體驗

[button color="info" icon="" url="" type=""]題目傳送門[/button]

有乙個長度為n的1~n的排列,現在進行m次刪除操作,每次給定刪除的元素,要求在每次刪除之前輸出序列裡的逆序對個數。

考慮最普通的靜態逆序對,顯然可以用樹狀陣列來維護,那麼每次刪除乙個數p,逆序對個數減少的就是(p前面大於p的數)和(p後面小於p的數),立馬就有乙個樸素的想法:在樹狀陣列裡修改刪除,但是馬上也就能把這個想法切掉,因為刪除操作開始後,所有數字已經加入進去了,此時的統計是沒有意義的。

那麼我們就要考慮如何完成這個維護這個順序的問題,另乙個想法就是用主席樹套樹狀陣列,但是我不會,所以讓我們來想想其他的辦法。

然後就考慮分塊。前面的塊裡的元素無論如何,一定在後面塊裡元素的前面。所以我們就考慮在刪除的元素的塊內暴力,其他的塊內直接利用前後關係來計算對答案的貢獻。

經過實踐,發現分100塊左右是最優的,就算卡滿時間複雜度也只有o(1000*m),大概5e7的時間複雜度,顯然是能卡過去的。

具體操作就是對每一塊需要查詢比某個元素x大或小的個數,那麼每一塊開兩個樹狀陣列就可以實現了,第乙個在1處插1,a[i]處插-1,這樣我們ask(x)得到的就是大於它的元素個數,第二個在a[i]處插1,ask(x)得到是小於它的元素個數。

至於上面說的暴力是怎麼暴力呢?真就列舉原數列判斷p前面比它大的,p後面比它小的,這個操作是o(塊長)的,上面那個整塊的操作是o(塊數logn)的,logn大致是17,整體是差不多在o(1000)這樣乙個級別,所以時間複雜度是正確的。

**實現也挺簡單的。。至少比機房那個打主席樹套樹狀陣列還沒調出來的簡單。

#include#define reg register

#define int long long

#define len 1000

#define l(x) ((x)*len-len+1)

#define r(x) ((x)*len)

#define lowbit(x) (x&-x)

using namespace std;

const int n=1e5+10,sn=110;

int a[n],num[n],c[sn][n][2];

int to[n],wz[n],vis[n],n,m;

inline int read()

while(ch>='0'&&ch<='9')

return x*f;

}inline void add(int u,int v,int pos,int p)

inline int ask(int u,int pos,int p)

inline void radd(int u,int v,int pos)

signed main()

} return 0;

}

Cqoi2011 動態逆序對

主席樹套樹狀陣列。主席樹第一題。鏈結靜態的逆序對問題很簡單,用線段樹或者是樹狀陣列即可解決。現在的問題是如何解決一道動態的逆序對問題?我們先把所有的逆序對統計出來。每次刪除數,我們可以把這個數對於逆序對個數的貢獻刪除出去。這個貢獻如何統計呢?front i 記錄i位置之前有多少個數比這個數大 bac...

CQOI2011 動態逆序對

這是一道cdq分治的好題,這道題的前置知識是cdq分治解決三維偏序問題,如果不會這個話請先自行學習。首先第乙個答案很顯然就是逆序對的數量,然後後面每次的刪除操作,我們考慮把這個被刪除的點原先的貢獻從答案中拿掉。我們用y表示這個點的數,del表示第幾個被刪除,若沒有被刪除則del m 1 考慮每個點的...

CQOI2011 動態逆序對

點此看題 考慮c dq cdqcd q,有三個值 t,d,v t,d,v t,d,v 要求t i t iti d i d idi v i vj v i v j vi vj 很容易看出來是三維偏序的板題,我們先保證t tt的有序,cdq cdqcd q的時候排序d dd,然後用樹狀陣列查詢v vv,貼...