BZOJ2141:排队(分块,树状数组)
Description
排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家
乐和和。红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍
高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足ihj的(i,j)数量。幼儿
园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的杂乱程度。为方便幼儿园阿
姨统计,在未进行任何交换操作时,你也应该输出该序列的杂乱程度。
Input
第一行为一个正整数n,表示小朋友的数量;
第二行包含n个由空格分隔的正整数h1,h2,…,hn,依次表示初始队列中小朋友的身高;
第三行为一个正整数m,表示交换操作的次数;
以下m行每行包含两个正整数ai和bi,表示交换位置ai与位置bi的小朋友。
1≤m≤2*10^3,1≤n≤2*104,1≤hi≤109,ai≠bi,1≤ai,bi≤n。
Output
输出文件共m行,第i行一个正整数表示交换操作i结束后,序列的杂乱程度。
Sample Input
【样例输入】
3
130 150 140
2
2 3
1 3
3
130 150 140
2
2 3
1 3
Sample Output
1
0
3
【样例说明】
未进行任何操作时,(2,3)满足条件;
操作1结束后,序列为130 140 150,不存在满足ihj的(i,j)对;
操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)
0
3
【样例说明】
未进行任何操作时,(2,3)满足条件;
操作1结束后,序列为130 140 150,不存在满足ihj的(i,j)对;
操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)
Solution
首先上来先离散化一下。
可以发现,交换两个位置对答案的影响只和两个位置中间的数的大小有关
所以可以分块加树状数组,两端零碎的暴力统计,中间成块的每一块开一个树状数组,就可以统计比两端大/小的数的个数了。
可以发现,交换两个位置对答案的影响只和两个位置中间的数的大小有关
所以可以分块加树状数组,两端零碎的暴力统计,中间成块的每一块开一个树状数组,就可以统计比两端大/小的数的个数了。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 #define N (20000+100) 7 using namespace std; 8 9 int n,m,unit,num,bnum,ans,l,r; 10 int a[N],b[N],L[N],R[N],ID[N]; 11 12 struct Node 13 { 14 int c[N]; 15 int lowbit(int x){return x&-x;} 16 void Update(int x,int v){for (;x<=n;c[x]+=v,x+=lowbit(x));} 17 int Query(int x){int s=0; for (;x;s+=c[x],x-=lowbit(x));return s;} 18 }T[150]; 19 20 void Init() 21 { 22 for (int i=1; i<=n; ++i) b[i]=a[i]; 23 sort(b+1,b+n+1); 24 bnum=unique(b+1,b+n+1)-b-1; 25 for (int i=1; i<=n; ++i) 26 a[i]=lower_bound(b+1,b+bnum+1,a[i])-b; 27 } 28 29 void Build() 30 { 31 unit=sqrt(n); 32 num=n/unit+(n%unit!=0); 33 for (int i=1; i<=num; ++i) 34 L[i]=(i-1)*unit+1,R[i]=i*unit; 35 R[num]=n; 36 for (int i=1; i<=num; ++i) 37 for (int j=L[i]; j<=R[i]; ++j) 38 ID[j]=i,T[i].Update(a[j],1); 39 } 40 41 void check(int x,int l,int r) 42 { 43 if (a[x]>a[l]) ans--; 44 if (a[x]<a[l]) ans++; 45 if (a[x]<a[r]) ans--; 46 if (a[x]>a[r]) ans++; 47 } 48 49 void Solve(int l,int r) 50 { 51 if (a[l]>a[r]) ans++; 52 if (a[l]<a[r]) ans--; 53 T[ID[l]].Update(a[l],1); T[ID[l]].Update(a[r],-1); 54 T[ID[r]].Update(a[r],1); T[ID[r]].Update(a[l],-1); 55 if (ID[l]==ID[r]) 56 { 57 for (int i=l+1; i<=r-1; ++i) 58 check(i,l,r); 59 printf("%d\n",ans); return; 60 } 61 for (int i=l+1; i<=R[ID[l]]; ++i) check(i,l,r); 62 for (int i=L[ID[r]]; i<=r-1; ++i) check(i,l,r); 63 for (int i=ID[l]+1; i<=ID[r]-1; ++i) 64 { 65 int l1=T[i].Query(a[l]-1); 66 int l2=T[i].Query(n)-T[i].Query(a[l]); 67 int r1=T[i].Query(a[r]-1); 68 int r2=T[i].Query(n)-T[i].Query(a[r]); 69 ans+=l1-l2+r2-r1; 70 } 71 printf("%d\n",ans); 72 } 73 74 int main() 75 { 76 scanf("%d",&n); 77 for (int i=1; i<=n; ++i) 78 scanf("%d",&a[i]); 79 Init(); Build(); 80 for (int i=1; i<=n; ++i) 81 { 82 ans+=T[0].Query(n)-T[0].Query(a[i]); 83 T[0].Update(a[i],1); 84 } 85 printf("%d\n",ans); 86 scanf("%d",&m); 87 for (int i=1; i<=m; ++i) 88 { 89 scanf("%d%d",&l,&r); if (l>r) swap(l,r); 90 swap(a[l],a[r]); Solve(l,r); 91 } 92 }