树状数组求逆序对
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组求逆序对相关的知识,希望对你有一定的参考价值。
1),输入n个值,求其中逆序对的个数:
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 #define ll long long 6 #define maxn 100005 7 using namespace std; 8 int c[maxn],n; 9 int low_bit(int i) 10 { 11 return i&(-i); 12 } 13 void update(int i,int v) 14 { 15 while(i<=n){ 16 c[i]+=v; 17 i+=low_bit(i); 18 } 19 } 20 int get_sum(int i) 21 { 22 int res=0; 23 while(i){ 24 res+=c[i]; 25 i-=low_bit(i); 26 } 27 return res; 28 } 29 int main() 30 { 31 scanf("%d",&n); 32 int ans=0; 33 for(int i=1;i<=n;i++){ 34 int a; 35 scanf("%d",&a); 36 update(a,1); 37 ans+=i-get_sum(a);/*getsum[a]表示a(包括a)前面有多少个1(即它前面有多少个数),假如有k个,此时一共往数组里加了i个数,那么有n-k个数大于它(由于这些数比a先输入,所以他们的位置在a前面,但它们的值比a大),那么由a构成的逆序对就有n-k个*/ 39 } 40 printf("%d\n",ans); 41 return 0; 42 }
输入n,m,表示有n个数和m个询问,每个询问输入两个数 l 和 r ,输出 [l,r] 这个区间内的逆序对个数。
我们可以在每次询问时通过移动区间的左右端点来维护结果:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int c[300001],a[300001],rpos=0,lpos=1,n,m,ans; 7 void add(int x,int d){ 8 while (x<=n){ 9 c[x]+=d; 10 x+=(x&(-x)); 11 } 12 } 13 int query(int x){ 14 int s=0; 15 while (x) 16 { 17 s+=c[x]; 18 x-=(x&(-x)); 19 } 20 return s; 21 } 22 int main() 23 { 24 //freopen("sort.in","r",stdin); 25 //freopen("sort.out","w",stdout); 26 int i,l,r; 27 cin>>n; 28 for (i=1;i<=n;i++){ 29 scanf("%d",&a[i]); 30 } 31 cin>>m; 32 for (i=1;i<=m;i++){ 33 scanf("%d%d",&l,&r);/*输入一个区间*/ 34 while (rpos<r){/*如果这个区间的右端点比原区间的右端点大,就加上从rpos+1到r这个区间内的数与其他数构成的逆序对*/ 35 rpos++; 36 ans+=query(n)-query(a[rpos]-1);/*n前面(包括n)的1的个数减去a[rpos]-1(包括a[rpos]-1)前面的1的歌数,剩下的就是*/ 37 add(a[rpos],1);/*a[rpos]-1后面,n前面的数的个数(即大于n的数),由于这些数比a[rpos]先输入,所以他们的位置在a[rpos]前面,所以他们就是a[rpos]的逆序对个数*/ 38 } 39 while (rpos>r){/*如果这个区间的右端点比原区间的右端点小,就减去从r+1到rpos这个区间内的数与其他数构成的逆序对*/ 40 add(a[rpos],-1); 41 ans-=query(n)-query(a[rpos]-1); 42 rpos--; 43 } 44 while (lpos<l){/*如果这个区间的左端点比原区间的右端点大,就减去从lpos到l-1这个区间内的数与其他数构成的逆序对*/ 45 add(a[lpos],-1); 46 ans-=query(a[lpos]-1); 47 lpos++; 48 } 49 while (lpos>l){/*如果这个区间的右端点比原区间的右端点小,就加上从l到rpos-1这个区间内的数与其他数构成的逆序对*/ 50 lpos--; 51 ans+=query(a[lpos]-1); 52 add(a[lpos],1); 53 } 54 printf("%d\n",ans);/*ans肯定不清零哇*/ 55 } 56 }
完~~~~~~
以上是关于树状数组求逆序对的主要内容,如果未能解决你的问题,请参考以下文章
HDU 1394 Minimum Inversion Number (树状数组求逆序对)