树状数组求逆序对

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 (树状数组求逆序对)

树状数组求逆序对

求逆序对(树状数组)

Another Version of Inversion 二维树状数组求逆序对

树状数组求逆序对