1. 程式人生 > >BZOJ3295[CQOI2011]動態逆序對(CDQ分治)

BZOJ3295[CQOI2011]動態逆序對(CDQ分治)

wid 方便 algorithm rgb 操作 排序 ron 它的 刪除

第一個不看題解A了的CDQ題目QwQ

Time Limit: 10 Sec Memory Limit: 128 MB

Description

對於序列A,它的逆序對數定義為滿足i<j,且Ai>Aj的數對(i,j)的個數。給1到n的一個排列,按照某種順序依次刪

除m個元素,你的任務是在每次刪除一個元素之前統計整個序列的逆序對數

Input

輸入第一行包含兩個整數n和m,即初始元素的個數和刪除的元素個數。

以下n行每行包含一個1到n之間的正整數,即初始排列。

以下m行每行一個正整數,依次為每次刪除的元素。

N<=100000 M<=50000

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)。


解析:

1.逆序對個數是滿足a[i]>a[j]&&i<j的(i, j)個數。

2.題目說刪除,不好處理,我們倒過來當成添加元素,統計每次添加元素會增加多少個逆序對,答案為依次累加的和。

3.一個操作除了可以用順序(也可理解為時間)和位置表示,為了方便還可擴展為順序(時間)、位置、數值三個指標表示,那麽對於(pos[i],a[i],time[i]),增加的逆序對個數等於滿足技術分享圖片 的j的個數(註意time的大小關系,因為是倒過來,時間大的先添加)。

4.沒有刪完的情況,剩下的部分人為地隨便順序刪掉就行,補齊n個操作。

5.答案會爆int。

然後就可以先對time排序,分兩半,右邊加進樹狀數組,更新左邊的答案,再遞歸處理兩半。

我的代碼很亂很亂很亂

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 struct Query
  8 {
  9 	int id, pos, val;
 10 }q[100010], tmp[100010];
 11
12 int n, m, cnt, pos[100010], arr[100010], tree[100010]; 13 long long ans[100010]; 14 15 void Add(int, int); 16 int query(int); 17 void CDQ(int, int); 18 bool cmp(Query, Query); 19 20 int main() 21 { 22 scanf("%d%d", &n, &m); 23 for(int i = 0; i < n; i++) 24 { 25 scanf("%d", arr + i); 26 pos[arr[i]] = i; 27 } 28 for(cnt = 0; cnt < m; cnt++) 29 { 30 int t; 31 scanf("%d", &t); 32 q[cnt].pos = pos[t]; 33 q[cnt].val = t; 34 q[cnt].id = cnt; 35 arr[pos[t]] = 0; 36 } 37 for(int i = 0; i < n; i++) 38 if(arr[i]) 39 { 40 q[cnt].pos = i; 41 q[cnt].val = arr[i]; 42 q[cnt].id = cnt; 43 cnt++; 44 } 45 sort(q, q + n); 46 CDQ(0, n - 1); 47 for(int i = n - 1; i >= 0; i--) 48 ans[i] += ans[i + 1]; 49 for(int i = 0; i < m; i++) 50 printf("%lld\n", ans[i]); 51 52 return 0; 53 } 54 void Add(int _pos, int val) 55 { 56 for(int i = _pos; i <= n; i += (i & (-i))) 57 tree[i] += val; 58 } 59 60 int query(int _pos) 61 { 62 int res = 0; 63 for(int i = _pos; i > 0; i -= (i & (-i))) 64 res += tree[i]; 65 return res; 66 } 67 68 bool operator <(Query a, Query b) 69 { 70 return a.pos < b.pos; 71 } 72 73 void CDQ(int l, int r) 74 { 75 if(l == r) return; 76 int mid = (l + r) >> 1; 77 for(int i = l; i <= r; i++) 78 if(q[i].id <= mid) ans[q[i].id] += (long long)query(n) - query(q[i].val); 79 else Add(q[i].val, 1); 80 for(int i = l; i <= r; i++) 81 if(q[i].id > mid) 82 Add(q[i].val, -1); 83 for(int i = r; i >= l; i--) 84 if(q[i].id <= mid) ans[q[i].id] += (long long)query(q[i].val); 85 else Add(q[i].val, 1); 86 for(int i = l; i <= r; i++) 87 if(q[i].id > mid) 88 Add(q[i].val, -1); 89 int l1 = l, l2 = mid + 1; 90 for(int i = l; i <= r; i++) 91 if(q[i].id <= mid) tmp[l1++] = q[i]; 92 else tmp[l2++] = q[i]; 93 for(int i = l; i <= r; i++) 94 q[i] = tmp[i]; 95 CDQ(l, mid); 96 CDQ(mid + 1, r); 97 } 98 //Rhein_E

這是一個悲傷的故事。。。。技術分享圖片

BZOJ3295[CQOI2011]動態逆序對(CDQ分治)