Bzoj 2141: 排队 分块,逆序对,树状数组
2141: 排队
Time Limit: 4 Sec Memory Limit: 259 MBSubmit: 1310 Solved: 517
[Submit][Status][Discuss]
Description
排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和。红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足ihj的(i,j)数量。幼儿园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的杂乱程度。为方便幼儿园阿姨统计,在未进行任何交换操作时,你也应该输出该序列的杂乱程度。
Input
第一行为一个正整数n,表示小朋友的数量;第二行包含n个由空格分隔的正整数h1,h2,…,hn,依次表示初始队列中小朋友的身高;第三行为一个正整数m,表示交换操作的次数;以下m行每行包含两个正整数ai和bi¬,表示交换位置ai与位置bi的小朋友。
Output
输出文件共m行,第i行一个正整数表示交换操作i结束后,序列的杂乱程度。
Sample Input
3
130 150 140
2
2 3
1 3
Sample Output
0
3
【样例说明】
未进行任何操作时,(2,3)满足条件;
操作1结束后,序列为130 140 150,不存在满足i<j且hi>hj的(i,j)对;
操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)。
【数据规模和约定】
对于100%的数据,1≤m≤2*103,1≤n≤2*104,1≤hi≤109,ai≠bi,1≤ai,bi≤n。
HINT
Source
给定一个序列,m次交换两个数,求初始逆序对数及每次交换后的逆序对数
首先离散化,分块,对于每块建立一个树状数组,保存这个块中的所有元素
然后对于每个询问(x,y) (x<y) 两侧的数是没有影响的,区间(x,y)的数a[i]讨论如下:
a[i]<a[x] --ans
a[i]>a[x] ++ans
a[i]<a[y] ++ans
a[i]>a[y] --ans
然后对于块中的树状数组处理,块外的暴力
注意此题元素有重复 亲测可信
RANK5吓尿0.0 为何块套树要比树套树还快……
------摘自Popoqqq
*********************************************************
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define MAXN 20010 4 int block,a[MAXN],b[MAXN],BIT[MAXN],pos[MAXN],ans,tot,n; 5 int read() 6 { 7 int s=0,fh=1;char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();} 9 while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();} 10 return s*fh; 11 } 12 int Lowbit(int o){return o&(-o);} 13 void Update(int o,int o1) 14 { 15 while(o<=tot) 16 { 17 BIT[o]+=o1; 18 o+=Lowbit(o); 19 } 20 } 21 int Sum(int o) 22 { 23 int sum=0; 24 while(o>0) 25 { 26 sum+=BIT[o]; 27 o-=Lowbit(o); 28 } 29 return sum; 30 } 31 void cl(int k) 32 { 33 int l=(k-1)*block+1,r=min(k*block,n),i; 34 for(i=l;i<=r;i++)b[i]=a[i]; 35 sort(b+l,b+r+1); 36 } 37 int Find(int l,int r,int find1) 38 { 39 int mid,ll=l,get=0; 40 while(l<=r) 41 { 42 mid=(l+r)/2; 43 if(b[mid]<find1){get=mid;l=mid+1;} 44 else r=mid-1; 45 } 46 if(get==0)return 0; 47 return (get-ll+1); 48 } 49 int Find1(int l,int r,int find1) 50 { 51 int mid,rr=r,get=0; 52 while(l<=r) 53 { 54 mid=(l+r)/2; 55 if(b[mid]>find1){get=mid;r=mid-1;} 56 else l=mid+1; 57 } 58 if(get==0)return 0; 59 return (rr-get+1); 60 } 61 void calc(int l,int r) 62 { 63 int L=pos[l],R=pos[r],i,gs,gs1; 64 if(a[l]>a[r])ans--; 65 if(a[l]<a[r])ans++; 66 if(L==R) 67 { 68 for(i=l+1;i<=r-1;i++) 69 { 70 if(a[i]>a[l])ans++; 71 if(a[i]<a[l])ans--; 72 if(a[i]>a[r])ans--; 73 if(a[i]<a[r])ans++; 74 } 75 swap(a[l],a[r]); 76 cl(L);cl(R); 77 return; 78 } 79 for(i=l+1;i<=L*block;i++) 80 { 81 if(a[i]>a[l])ans++; 82 if(a[i]<a[l])ans--; 83 if(a[i]>a[r])ans--; 84 if(a[i]<a[r])ans++; 85 } 86 for(i=L+1;i<=R-1;i++) 87 { 88 gs=Find((i-1)*block+1,min(i*block,n),a[l]); 89 ans-=gs; 90 gs1=Find((i-1)*block+1,min(i*block,n),a[r]); 91 ans+=gs1; 92 gs=Find1((i-1)*block+1,min(i*block,n),a[l]); 93 ans+=gs; 94 gs1=Find1((i-1)*block+1,min(i*block,n),a[r]); 95 ans-=gs1; 96 } 97 for(i=(R-1)*block+1;i<=r-1;i++) 98 { 99 if(a[i]>a[l])ans++; 100 if(a[i]<a[l])ans--; 101 if(a[i]>a[r])ans--; 102 if(a[i]<a[r])ans++; 103 } 104 swap(a[l],a[r]); 105 cl(L);cl(R); 106 } 107 int main() 108 { 109 freopen("nt2011_queue.in","r",stdin); 110 freopen("nt2011_queue.out","w",stdout); 111 int i,ai,bi,m,M,wz; 112 n=read(); 113 block=(int)sqrt(n); 114 for(i=1;i<=n;i++)a[i]=read(),b[i]=a[i]; 115 sort(b+1,b+n+1); 116 tot=unique(b+1,b+n+1)-(b+1); 117 memset(BIT,0,sizeof(BIT)); 118 //for(i=1;i<=tot;i++)Update(i,1); 119 ans=0; 120 for(i=n;i>=1;i--) 121 { 122 wz=lower_bound(b+1,b+tot+1,a[i])-b; 123 ans+=Sum(wz-1); 124 Update(wz,1); 125 a[i]=wz; 126 } 127 /*for(i=1;i<=n;i++) 128 { 129 a[i]=lower_bound(b+1,b+tot+1,a[i])-b; 130 ans+=Sum(a[i]-1); 131 if(BIT[a[i]]!=0)Update(a[i],-1); 132 }*/ 133 printf("%d\n",ans); 134 for(i=1;i<=n;i++)pos[i]=(int)(i-1)/block+1; 135 if(n%block==0)M=n/block; 136 else M=n/block+1; 137 for(i=1;i<=M;i++)cl(i); 138 m=read(); 139 for(i=1;i<=m;i++) 140 { 141 ai=read();bi=read(); 142 if(ai>bi)swap(ai,bi); 143 calc(ai,bi); 144 printf("%d\n",ans); 145 } 146 fclose(stdin); 147 fclose(stdout); 148 return 0; 149 }