1. 程式人生 > >計蒜客D2T2 蒜頭君的排序(動態維護樹狀數組)

計蒜客D2T2 蒜頭君的排序(動態維護樹狀數組)

我們 long long for include names pri ont 思考 ||

蒜頭君的排序(sort)

2000ms 262144K

蒜頭君是一個愛思考的好孩子,這一天他學習了冒泡排序,於是他就想,把一個亂序排列通過冒泡排序排至升序需要多少次交換,這當然難不倒他,於是他想來點刺激的,給定一個1…n1的排列,每次從該排列中選擇一個區間[l,r],問使用冒泡排序將該區間排至升序需要多少次交換操作。

輸入格式

第一行一個整數n,表示排列長度。

接下來一行n個整數,表示該排列。

接下來一行一個整數m,表示詢問次數。

接下來m 行,每行2個整數l,r,表示詢問[l,r] 區間。

輸出格式

輸出m行,每行1個整數,第i行表示第i個詢問的答案。

數據規模

對於30%的數據,滿足1≤n,m≤300;

對於60%的數據,滿足1≤n,m≤1000;

對於100%的數據,滿足1≤n,m≤30000,l<r,l<r,∑∣l[i]?l[i?1]|+∑∣r[i]?r[i?1]∣≤ 7*10^6??。

樣例輸入

樣例輸入

10

9 8 7 4 5 6 10 3 2 1

5

2 4

8 10

2 8

5 9

4 9

樣例輸出

3

3

13

7

9

解析:這道題直接暴力(直接用冒泡排序或歸並排序記錄逆序對)可以拿60分;

   離線使用樹狀數組維護能得70分;

   在線維護樹狀數組可以拿100分。。。(為什麽離線會超時。。)

關於樹狀數組的維護我們可以先定義兩個指針分別指向左端點和右端點,每次查詢時不斷的維護這段區間(左端點,右端點不斷的向左向右移),即可查詢到所有的答案(好神奇。。)

十分不解為什麽不能先按照左端點的位置排序,後維護,這樣可以少進行一個左端點向左的步驟。。可惜會超時;

關於如何從[l,r]變成[l-1,r],[l+1,r],[l,r-1],[l,r+1],自己手動模擬一遍就知道了,第一次感覺好玄學。。。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #define lo(x) (x&(-x))
 6 #define ll long long
 7 #define
man 30010 8 using namespace std; 9 //common 10 int n,m,c[man],pos[man],ask[man]; 11 ll a[man],b[man]; 12 inline int read() 13 { int x=0;bool f=0; 14 char ch=getchar(); 15 while(ch<0||ch>9){f=(ch==45);ch=getchar();} 16 while(ch>=0&&ch<=9){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} 17 return f?(~x+1):x; 18 } 19 struct range 20 { int x,y,id;}e[man]; 21 //lowbit 22 inline void add(int x,int val) 23 { while(x<=n) 24 { c[x]+=val; 25 x+=lo(x); 26 } 27 return ; 28 } 29 inline int calc(int x) 30 { int ans=0; 31 while(x>0) 32 { ans+=c[x]; 33 x-=lo(x); 34 } 35 return ans; 36 } 37 int main() 38 { freopen("sort.in","r",stdin); 39 freopen("sort.out","w",stdout); 40 n=read(); 41 for(int i=1;i<=n;i++) 42 scanf("%lld",&a[i]),b[i]=a[i]; 43 sort(a+1,a+1+n); 44 for(int i=1;i<=n;i++) 45 pos[i]=lower_bound(a+1,a+n+1,b[i])-a; 46 m=read(); 47 for(int i=1;i<=m;i++) 48 { e[i].x=read();e[i].y=read();e[i].id=i;} 49 int l=1,r=0,ans=0; 50 for(int i=1;i<=m;i++) 51 { while(r<e[i].y) 52 { r++; 53 ans+=calc(n)-calc(pos[r]-1); 54 add(pos[r],1); 55 } 56 while(l<e[i].x) 57 { add(pos[l],-1); 58 ans-=calc(pos[l]-1); 59 l++; 60 } 61 while(r>e[i].y) 62 { add(pos[r],-1); 63 ans-=calc(n)-calc(pos[r]-1); 64 r--;} 65 while(l>e[i].x) 66 { l--; 67 ans+=calc(pos[l]-1); 68 add(pos[l],1); 69 } 70 ask[e[i].id]=ans; 71 } 72 for(int i=1;i<=m;i++) 73 printf("%d\n",ask[i]); 74 return 0; 75 }

計蒜客D2T2 蒜頭君的排序(動態維護樹狀數組)