題目鏈結
對於序列a,它的逆序對數定義為滿足iaj的數對(i,j)的個數。給1到n的乙個排列,按照某種順序依次刪
除m個元素,你的任務是在每次刪除乙個元素之前統計整個序列的逆序對數
input
輸入第一行包含兩個整數n和m,即初始元素的個數和刪除的元素個數。
以下n行每行包含乙個1到n之間的正整數,即初始排列。
以下m行每行乙個正整數,依次為每次刪除的元素。
n<=100000 m<=50000
output
輸出包含m行,依次為刪除每個元素之前,逆序對的個數。
sample input
5 4153
4251
42sample output52
21樣例解釋
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
hint
source
在網上看了許多的題解發現有多種做法, 但主要分為兩類一種為cdq分治, 一種為樹套樹的做法。其中樹套樹中,樹狀陣列套線段樹的**是最為簡潔易懂的但缺點也很明顯,就是所需要的空間較大。其具體做法為在樹狀陣列中的每個點上都開乙個線段樹(維護樹狀陣列上對應的區間的數, 線段樹上的每個點維護對應值區間內數的多少),這樣便於查詢在樹狀陣列上的區間l ~ r中比x小的數字有多少,又由於所需空間較大故採取動態開點,細節見於**。
#include
using
namespace std;
#define lowbit(x) x & -x
#define ll long long
const
int n =
1e5+10;
const
int m =
9e6+10;
int n, m;
int ls[m]
, rs[m]
, tr[m]
, pos[n]
, cnt;
// tr[i]第i個區間中的數字的數量, pos[i], 值 i 為的數在樹狀陣列中的位置
int t[n]
;// 樹狀陣列
ll ans;
void
insert_
(int
&k,int l,
int r,
int x)
intquery
(int k,
int l,
int r,
int x,
int y)
void
update
(int k,
int l,
int r,
int x)
intmain()
while
(m --
)for
(int i = pos[x]
; i <= n; i +
=lowbit
(i))
update
(t[i],1
, n, x);}
return0;
}
動態逆序對
容易寫掛 對於新手與蒟蒻 洛谷 cdq 如果按照三維偏序那樣求,那麼會漏掉一些情況。所以要跑兩遍cdq。兩遍cdq又會有乙個問題,就是判等於的問題。第一遍cdq第三維判等於,第二遍判不等於.include define ll long long using namespace std inline ...
動態逆序對 CDQ
cdq二層試煉 bzoj3295 題意大致是 給你乙個序列 乙個1 n的排列 每次刪掉乙個數,求刪掉之前的逆序對。方案1 強行模擬,每次刪掉乙個乙個數,在剩下的數裡面用歸併求逆序對,複雜度o mnlogn 這個複雜度明顯是不能接受的 方案2 樹套樹,量令人傷心。方案3 cdq分治。之前已經寫過一篇 ...
動態逆序對 CDQ分治
對於序列a,它的逆序對數定義為滿足iaj的數對 i,j 的個數。給1到n的乙個排列,按照某種順序依次刪除m個元素,你的任務是在每次刪除乙個元素之前統計整個序列的逆序對數。輸入格式 輸入第一行包含兩個整數n和m,即初始元素的個數和刪除的元素個數。以下n行每行包含乙個1到n之間的正整數,即初始排列。以下...