zoukankan      html  css  js  c++  java
  • 树状数组求逆序对

    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
    ",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
    ",ans);/*ans肯定不清零哇*/
    55     }
    56 }

    完~~~~~~

  • 相关阅读:
    优化eclipse
    Servlet与jsp间的传值问题
    servlet & javabean
    Java数据类型
    CentOS 7 安装tomcat
    Nginx配置详解
    PHP文件缓存实现
    lnmp编译安装
    Php安全规范
    php编码规范
  • 原文地址:https://www.cnblogs.com/Miroerwf/p/7779704.html
Copyright © 2011-2022 走看看