1. 程式人生 > >[BZOJ3295][Cqoi2011]動態逆序對 CDQ分治&樹套樹

[BZOJ3295][Cqoi2011]動態逆序對 CDQ分治&樹套樹

的確 分治 mat fda 應該 through tex 瓶頸 這樣的

3295: [Cqoi2011]動態逆序對

Time Limit: 10 Sec Memory Limit: 128 MB

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

題解:

啊啊啊這道題真的是差點把自己打死

跟zyfdalao分享了一下思路然後他就按我的思路A了可是我自己卻不會了

如果你是樹套樹玩家,請移步:http://www.cnblogs.com/TSHugh/p/7001884.html

在具體寫題解之前,我要分享一個面對瓶頸很好的做法(我這樣反復理了三遍,思路一遍比一遍清晰...遇到瓶頸的時候真的很推薦這樣做):

思路不通了把所有已知條件再列出來一邊,寫清變量之間的關系和限制,並且針對每一個條件寫出解決方案和打法

感覺淩亂的代碼段就刪掉重打一遍,用的總時間一定會比死調下去少

首先一個小優化:把val變成n-val+1,這樣原來的逆序對就變成了現在的順序對,個人感覺更加好操作.

我們考慮,我們可以利用樹狀數組求出一開始總的逆序對數,並且同時利用樹狀數組求出以每個位置為開頭和結尾的逆序對個數,

我們設num數組表示這個數目,num[0][i]表示以i位置結尾的逆序對個數,num[1][i]表示以i位置開頭的逆序對個數.

這樣的話,每次我們先輸出當前的總數,再減去num[0][i]+num[1][i],然後...

我們發現有一些不對,如果原來形成的逆序對的另外那個數已經被刪除了,那麽這一對就不應該被減去

所以我們考慮再計算一個delta表示這個增量:

其中delta[0][i]表示以i位置結尾,但是另外那個數比i刪除的早的逆序對個數,

delta[1][i]表示以i位置開頭,但是另外那個數比i刪除的早的逆序對個數.

接下來我們考慮什麽樣的數對(i,j)會被記入delta

如果設i位置的數的刪除時間是tim[i](沒有被刪除的數的刪除時間順次設成m+1~n即可,他們的delta不會被記入答案)

設i位置的數值是val[i](這裏的val已經進行了n-val+1取反操作)

那麽delta[0][i]裏的數應該滿足:

tim[i]>tim[j]

val[i]>val[j]

i>j

delta[1][i]裏的數應該滿足:

tim[i]>tim[j]

val[i]<val[j]

i<j

那麽上面這兩組約束條件(尤其是第一組)很像一個三維偏序的統計問題.

的確如此,我們只需要用CDQ分治統計一下符合條件的數對數即可.

拿我的思路來說,我們可以讓時間有序,給下標排序,用樹狀數組維護權值val,

這樣跑兩遍CDQ統計符合條件的偏序對數,就能分別計算delta[0][i]和delta[1][i]

最後輸出答案時,先輸出答案ans,然後給ans減去num[0][i]+num[1][i],再加上delta[0][i]+delta[1][i],這樣就能正確的維護逆序對數了,

代碼實現:

 1 #include <cstring>
 2 #include <cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef long long LL;
 6 const int N=100010,M=50010;
 7 struct node
 8 {
 9     int tim,val,pos;
10     node (int a=0,int b=0,int c=0){tim=a,val=b,pos=c;}
11 }q[N];
12 int cnt,n,m,a[N],match[N],step[M];
13 bool vis[N];
14 LL delta[2][N],num[2][N],bit[N];
15 inline int lowbit(int a){return a&-a;}
16 inline void add(int a,LL b)
17     {while(a<=n)bit[a]+=b,a+=lowbit(a);}
18 inline LL sum(int a)
19     {LL ret=0;while(a)ret+=bit[a],a-=lowbit(a);return ret;}
20 inline void gsum0()
21 {
22     for(register int i=1;i<=n;++i)
23         num[0][i]=sum(a[i]),add(a[i],1);
24     memset(bit,0,sizeof(bit));
25 }
26 inline void gsum1()
27 {
28     for(register int i=n;i;--i)
29         num[1][i]=sum(a[i]),add(1,1),add(a[i],-1);
30     memset(bit,0,sizeof(bit));
31 }
32 inline void readin()
33 {
34     register int i;scanf("%d%d",&n,&m);
35     for(i=1;i<=n;++i)
36         scanf("%d",&a[i]),a[i]=n-a[i]+1,match[a[i]]=i;
37     gsum0();gsum1();
38     for(i=1;i<=m;++i)
39         scanf("%d",&step[i]),step[i]=n-step[i]+1,vis[step[i]]=1;
40 }
41 inline bool mt1(const node &a,const node &b){return a.pos<b.pos;}
42 inline bool mt2(const node &a,const node &b){return a.tim<b.tim;}
43 inline void CDQ0(int l,int r)
44 {
45     if(l==r)return;
46     register int mi=l+r>>1,i;
47     CDQ0(l,mi);CDQ0(mi+1,r);
48     sort(q+l,q+r+1,mt1);
49     for(i=l;i<=r;++i)
50         if(q[i].tim<=mi)add(q[i].val,1);
51         else delta[0][q[i].tim]+=sum(q[i].val);
52     for(i=l;i<=r;++i)
53         if(q[i].tim<=mi)add(q[i].val,-1);
54 }
55 inline void CDQ1(int l,int r)
56 {
57     if(l==r)return;
58     register int mi=l+r>>1,i;
59     CDQ1(l,mi);CDQ1(mi+1,r);
60     sort(q+l,q+r+1,mt1);
61     for(i=r;i>=l;--i)
62         if(q[i].tim<=mi)add(1,1),add(q[i].val,-1);
63         else delta[1][q[i].tim]+=sum(q[i].val);
64     for(i=r;i>=l;--i)
65         if(q[i].tim<=mi)add(1,-1),add(q[i].val,1);
66 }
67 int main()
68 {
69     register int i;readin();
70     for(i=1;i<=m;++i)
71         q[++cnt]=node(cnt,step[i],match[step[i]]);
72     for(i=1;i<=n;++i)
73         if(!vis[a[i]])q[++cnt]=node(cnt,a[i],i);
74     CDQ0(1,n),sort(q+1,q+n+1,mt2),CDQ1(1,n);
75     LL ans=0;int pos;
76     for(i=1;i<=n;++i)ans+=num[0][i];
77     for(i=1;i<=m;++i)
78     {
79         printf("%lld\n",ans),pos=match[step[i]],
80         ans-=(num[0][pos]+num[1][pos]),
81         ans+=(delta[0][i]+delta[1][i]);
82     }
83 }

[BZOJ3295][Cqoi2011]動態逆序對 CDQ分治&樹套樹