1. 程式人生 > >[BZOJ3295][Cqoi2011]動態逆序對

[BZOJ3295][Cqoi2011]動態逆序對

兩個 rip 任務 i++ stat ans tput 依次 scu

3295: [Cqoi2011]動態逆序對

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 5276 Solved: 1783
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

5 4
1
5
3
4
2
5
1
4
2

Sample Output

5
2
2
1

樣例解釋
(1,5,3,4,2)?(1,3,4,2)?(3,4,2)?(3,2)?(3)。

HINT

N<=100000 M<=50000

cdq分治裸題。

首先我們把刪除改為倒序插入,對於每一個操作,我們記錄三元組(x,y,z)表示位置為x數值為y操作時間為z。此時,我們要求對於每一個(x,y,z)的z0<z&&x0<x&&y0》y。

我們首先考慮對於z從小到大排序,這樣,我們就能忽略z的影響。此時,我們要求x0<x&&y0>y的組數。

現在我們開始分治。

首先對於區間(l,r),區間(l,mid)中所有元素的z都小於(mid+1,r)中所有元素的z,所以我們考慮(l,mid)中的修改對(mid+1,r)中的每個元素的影響。

現在我們對區間(l,mid)中的所有元素打上標記,使其成為修改操作,對於區間(mid+1,r)中的所有元素打上標記,使其成為詢問操作。

我們對區間(l,r)以x為第一關鍵字排序,這樣,我們要求的就是a[i].y<a[j].y(i>j) a[i].y>a[j].y(i<j)的個數,可以用樹狀數組維護。

處理完區間(l,r),我們可以分治處理(l,mid)(mid+1,r)

技術分享
 1
#include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 int n,m; 9 struct data 10 { 11 int x,y,z; 12 int flag; 13 }a[100008],b[100008]; 14 int w[100008]; 15 bool cmp1(data s1,data s2){return s1.z<s2.z;} 16 bool cmp2(data s1,data s2){return s1.x<s2.x;} 17 int tre[100008]; 18 long long ans[100008]; 19 int lowbit(int x){return x&(-x);} 20 void update(int x,int ad){for(int i=x;i<=n;i+=lowbit(i)) tre[i]+=ad;} 21 int query(int x) 22 { 23 int re=0; 24 for(int i=x;i>0;i-=lowbit(i)) re+=tre[i]; 25 return re; 26 } 27 void cdq(int l,int r) 28 { 29 if(l>=r) return; 30 int mid=(l+r)>>1; 31 int cnt=0; 32 for(int i=l;i<=r;i++) 33 { 34 if(i<=mid){b[++cnt]=a[i];b[cnt].flag=0;} 35 else {b[++cnt]=a[i];b[cnt].flag=1;} 36 } 37 sort(b+1,b+cnt+1,cmp2); 38 for(int i=1;i<=cnt;i++) 39 { 40 if(!b[i].flag) update(b[i].y,1); 41 else ans[b[i].z]+=(long long)(query(n)-query(b[i].y)); 42 } 43 for(int i=1;i<=cnt;i++) if(!b[i].flag) update(b[i].y,-1); 44 for(int i=cnt;i>=1;i--) 45 { 46 if(!b[i].flag) update(b[i].y,1); 47 else ans[b[i].z]+=(long long)query(b[i].y); 48 } 49 for(int i=1;i<=cnt;i++) if(!b[i].flag) update(b[i].y,-1); 50 cdq(l,mid); cdq(mid+1,r); 51 } 52 int main() 53 { 54 scanf("%d%d",&n,&m); 55 int c=n; 56 for(int i=1;i<=n;i++) 57 { 58 a[i].x=i;scanf("%d",&a[i].y);w[a[i].y]=i; 59 } 60 for(int i=1;i<=m;i++) 61 { 62 int t; 63 scanf("%d",&t); 64 a[w[t]].z=c--; 65 } 66 for(int i=n;i>=1;i--) if(!a[i].z) a[i].z=c--; 67 sort(a+1,a+n+1,cmp1); 68 cdq(1,n); 69 for(int i=1;i<=n;i++) ans[i]+=ans[i-1]; 70 for(int i=n;i>=n-m+1;i--) printf("%lld\n",ans[i]); 71 }
View Code

[BZOJ3295][Cqoi2011]動態逆序對