time limit: 10 sec
memory limit: 128 mb
submit: 3122
solved: 986 [
submit][
status][
discuss]
對於序列a,它的逆序對數定義為滿足i
>aj
的數對(i,j)的個數。給1到n的乙個排列,按照某種順序依次刪除m個元素,你的任務是在每次刪除乙個元素之前統計整個序列的逆序對數。
輸入第一行包含兩個整數n和m,即初始元素的個數和刪除的元素個數。以下n行每行包含乙個1到n之間的正整數,即初始排列。以下m行每行乙個正整數,依次為每次刪除的元素。
輸出包含m行,依次為刪除每個元素之前,逆序對的個數。
5 415
3425
1425
221樣例解釋
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
n<=100000 m<=50000
方法一:各種
樹套樹,目測**難度較大
方法二:
cdq分治
+樹狀陣列
將刪除操作逆向,轉化成新增操作。
於是問題轉化成每次向序列中新增乙個數,詢問逆序對數。
考慮每次加入乙個數對答案的影響,它會與前面並且大於它的數和後面並且小於它的數構成逆序對。
然後在cdq分治裡做兩次就可以了。
#include#include#include#include#include#include#define f(i,j,n) for(int i=j;i<=n;i++)
#define d(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 100005
using namespace std;
int n,m,pos[maxn],c[maxn],sl[maxn],sr[maxn];
ll ans[maxn];
struct dataa[maxn],b[maxn];
inline int read()
while (ch>='0'&&ch<='9')
return x*f;
}inline void add(int x,int y)
inline int query(int x)
inline void cdq(int l,int r)
f(i,l,r) a[i]=b[i];
tmp=l;
f(i,mid+1,r)
f(i,tmp+1,mid) add(a[i].v,-1);
cdq(l,mid);cdq(mid+1,r);
}int main()
Cqoi2011 BZOJ3295 動態逆序對
對於序列a,它的逆序對數定義為滿足i 樹狀陣列 一看到逆序對就要想到樹狀陣列。維護每個數前面到目前有多少個比自己大。動態的思路 因為要動態維護,每次只刪掉乙個數在逆序對中的貢獻 及每個數前面有多少個比自己大,每個數後面有多少數比自己小。先預處理出每個數前面有多少個比自己大ll i 每個數後面有多少個...
bzoj3295 Cqoi2011 動態逆序對
傳送門 題解 cdq分治 我們仔細想一想維護逆序對的時候我們用的不就是歸併排序嗎?而歸併排序不就可以看作一種分治嗎?於是此題走上正軌,我們可以用分治來寫 怎麼寫?我們刪除乙個點,損失了什麼?1.這個點x之前比我大的個數記為big x 這個點x之後比我小的記作small x 那麼損失 small x ...
bzoj3295 Cqoi2011 動態逆序對
對於序列a,它的逆序對數定義為滿足 i j,且a i a j的數對 i,j 的個數。給1到 n的乙個排列,按照某種順序依次刪除 m個元素,你的任務是在每次刪除乙個元素之前統計整個序列的逆序對數。輸入第一行包含兩個整數 n和m,即初始元素的個數和刪除的元素個數。以下 n行每行包含乙個1到 n之間的正整...