CQOI2011 動態逆序對

2022-05-09 11:59:36 字數 1738 閱讀 2928

嘟嘟嘟

雙倍經驗

這道題只要想明白了就和\(cdq\)分治的板兒沒什麼區別了,然而如果想不明白就會像我一樣磨嘰了一晚上。

刪數不好辦,於是離線倒序改成加數。

考慮加上乙個數\(a_i\)形成的逆序對:1.在他前面且比他大的。2.在他後面且比他小的。

因為數字是動態新增的,所以上述的數必須是在他之前新增的!

如果給每乙個數三個屬性:\(x, tim, val\),分別表示這個數的位置,新增時間和大小。那麼上面的兩條就可以形式化的寫成:

$ x_j < x_i, tim_j < tim_i,val_j > val_i\(

\)x_j > x_i, tim_j < tim_i, val_j < val_i\(

這不就是陌上花開嗎!

於是我們按\)x\(排序,然後歸併排序\)tim\(,並用樹狀陣列維護\)val$。

需要注意的是成立條件有兩條,因此我們在分治的每一層要歸併兩次,第一次統計右邊的數形成的逆序對個數,第二次統計左邊的數形成的逆序對個數。

#include#include#include#include#include#include#include#include#include#includeusing namespace std;

#define enter puts("")

#define space putchar(' ')

#define mem(a, x) memset(a, x, sizeof(a))

#define rg register

typedef long long ll;

typedef double db;

const int inf = 0x3f3f3f3f;

const db eps = 1e-8;

const int maxn = 1e5 + 5;

inline ll read()

inline void write(ll x)

int n, m, pos[maxn];

struct node

a[maxn], t[maxn];

int c[maxn];

int lowbit(int x)

void erase(int pos)

void add(int pos, int d)

int query(int pos)

ll ans[maxn];

void cdqsolve(int l, int r)

else

}for(int i = l; i <= mid; ++i) erase(a[i].val);

id1 = l; id2 = mid + 1;

for(int i = l; i <= r; ++i)

else

}for(int i = mid + 1; i <= r; ++i) erase(a[i].val);

for(int i = l; i <= r; ++i) a[i] = t[i];

}int main()

int t = m;

for(int i = 1; i <= m; ++i)

cdqsolve(1, n);

for(int i = 1; i <= m; ++i) ans[i] = ans[i - 1] + ans[i];

for(int i = m; i; --i) write(ans[i]), enter;

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,貼...