動態逆序對 CDQ分治

2021-08-29 14:10:55 字數 1258 閱讀 9419

對於序列a,它的逆序對數定義為滿足iaj的數對(i,j)的個數。給1到n的乙個排列,按照某種順序依次刪除m個元素,你的任務是在每次刪除乙個元素之前統計整個序列的逆序對數。

輸入格式:

輸入第一行包含兩個整數n和m,即初始元素的個數和刪除的元素個數。以下n行每行包含乙個1到n之間的正整數,即初始排列。以下m行每行乙個正整數,依次為每次刪除的元素。

輸出格式:

輸出包含m行,依次為刪除每個元素之前,逆序對的個數。

輸入樣例#1:

5 415

3425

142

輸出樣例#1:

522

1樣例解釋

(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

n<=100000 m<=50000

將刪除看做倒著插入,記錄三元組

time表示第幾個插入,很明顯第乙個刪除的time為n

pos表示在原佇列中的位置

val表示值

我們按time排序,發現對當前time的答案有貢獻的為

time_ipos_i>pos && val_i或者 pos_ival

於是就是3維偏序問題了

#include#define n 200005

#define ll long long

using namespace std;

struct nodeq[n],tmp[n];

int n,m,time,a[n],match[n],c[n];

ll ans[n];

bool cmp(node a,node b)

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

if(q[i].t<=mid) add(q[i].y,-1);

}int main()

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

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

if(q[i].t==0) q[i].t=time--;

sort(q+1,q+n+1,cmp);

cdq(1,n);

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

for(int i=n;i>=n-m+1;i--) printf("%lld\n",ans[i]);

return 0;

}

動態逆序對 CDQ

cdq二層試煉 bzoj3295 題意大致是 給你乙個序列 乙個1 n的排列 每次刪掉乙個數,求刪掉之前的逆序對。方案1 強行模擬,每次刪掉乙個乙個數,在剩下的數裡面用歸併求逆序對,複雜度o mnlogn 這個複雜度明顯是不能接受的 方案2 樹套樹,量令人傷心。方案3 cdq分治。之前已經寫過一篇 ...

Luogu1393 動態逆序對(CDQ分治)

對於給定的一段正整數序列,我們定義它的逆序對的個數為序列中ai aj且i j的有序對 i,j 的個數。你需要計算出乙個序列的逆序對組數及其刪去其中的某個數的逆序對組數。輸入格式 第一行,兩個數n,m,表示序列中有n個數,要刪去m個數 第二行n個數,表示給定的序列。第三行m個數,第i個數di表示要刪去...

bzoj3295 動態逆序對(CDQ分治)

time limit 10 sec memory limit 128 mb submit 7178 solved 2548 submit status discuss 對於序列a,它的逆序對數定義為滿足iaj的數對 i,j 的個數。給1到n的乙個排列,按照某種順序依次刪 除m個元素,你的任務是在每次...