BZOJ3289 Mato的文件管理(莫队算法+树状数组)
题目是区间逆序数查询。
莫队算法。。左或右区间向左或右延伸时加或减这个区间小于或大于新数的数的个数,这个个数用树状数组来统计,我用线段树超时了。询问个数和数字个数都记为n,数字范围不确定所以离散化,这样时间复杂度就是$O(n^{\frac32}\log{n})$
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 #define MAXN 55555 7 int block; 8 struct Query{ 9 int i,l,r; 10 bool operator<(const Query &q)const{ 11 if(l/block==q.l/block) return r<q.r; 12 return l/block<q.l/block; 13 } 14 }que[MAXN]; 15 16 int bit[MAXN],N; 17 inline int lowbit(int x){ 18 return x&(-x); 19 } 20 void update(int x,int k){ 21 while(x<=N){ 22 bit[x]+=k; 23 x+=lowbit(x); 24 } 25 } 26 int query(int x){ 27 if(x<=0) return 0; 28 int res=0; 29 while(x){ 30 res+=bit[x]; 31 x-=lowbit(x); 32 } 33 return res; 34 } 35 36 int b[MAXN],bn,res,tot; 37 void insertR(int i){ 38 i=lower_bound(b+1,b+1+bn,i)-b; 39 res+=tot-query(i); 40 update(i,1); 41 ++tot; 42 } 43 void removeR(int i){ 44 i=lower_bound(b+1,b+1+bn,i)-b; 45 res-=tot-query(i); 46 update(i,-1); 47 --tot; 48 } 49 void insertL(int i){ 50 i=lower_bound(b+1,b+1+bn,i)-b; 51 res+=query(i-1); 52 update(i,1); 53 ++tot; 54 } 55 void removeL(int i){ 56 i=lower_bound(b+1,b+1+bn,i)-b; 57 res-=query(i-1); 58 update(i,-1); 59 --tot; 60 } 61 int a[MAXN],ans[MAXN]; 62 int main(){ 63 int n,m; 64 scanf("%d",&n); 65 block=(int)sqrt(n); 66 for(int i=1; i<=n; ++i){ 67 scanf("%d",&a[i]); 68 b[i]=a[i]; 69 } 70 sort(b+1,b+1+n); 71 bn=unique(b+1,b+1+n)-b-1; 72 N=bn; 73 scanf("%d",&m); 74 for(int i=0; i<m; ++i){ 75 que[i].i=i; 76 scanf("%d%d",&que[i].l,&que[i].r); 77 } 78 sort(que,que+m); 79 int l=1,r=1; insertR(a[1]); 80 for(int i=0; i<m; ++i){ 81 while(l<que[i].l) removeL(a[l++]); 82 while(l>que[i].l) insertL(a[--l]); 83 while(r>que[i].r) removeR(a[r--]); 84 while(r<que[i].r) insertR(a[++r]); 85 ans[que[i].i]=res; 86 } 87 for(int i=0; i<m; ++i){ 88 printf("%d\n",ans[i]); 89 } 90 return 0; 91 }