• 树状数组求逆序数的原理


           求逆序数的方法有很多,比如归并排序,但本文重点讲一下如何用树状数组来求逆序数。

           当数据的范围较小时,比如maxn=100000,那么我们可以开一个数组c[maxn],来记录前面数据的出现情况,初始化为0;当数据a出现时,就令c[a]=1。这样的话,     欲求某个数a的逆序数,只需要算出在当前状态下c[a+1,maxn]中有多少个1,因为这些位置的数在a之前出现且比a大。但是若每添加一个数据a时,就得从a+1到      maxn搜一遍,复杂度太高了。树状数组却能很好的解决这个问题,同样开一个数组d[maxn],初始化为0,d[i]记录下i结点所管辖范围内当前状态有多少个数;当添加数     据a时,就向上更新d,这样一来,欲求a的逆序数时,只需要算sum(maxn)-sum(a);sum(i)表示第i个位置之前出现了多少个1. 

       举个例子:有5个数,分别为5 3 4 2 1,当读入数据a=5时,c为:0,0,0,0,1;d为:0,0,0,0,1;当读入数据a=3时,c为:0,0,1,0,1;d为:0,0    1,1,1;当读入数据a=4时,c为:0,0,1,1,1;d为:0,0,1,2,1;…………。

           此思想的关键在于,读入数据的最大值为maxn,由于maxn较小,所以可以用数组来记录状态。当maxn较大时,直接开数组显然是不行了,这是的解决办法就是离散   化。所谓离散化,就是将连续问题的解用一组离散要素来表征而近似求解的方法,这个定义太抽象了,还是举个例子吧。

       假如现在有一些数:1234 98756 123456 99999 56782,由于1234是第一小的数,所以num[1]=1;依此,有num[5]=2,num[2]=3,num[4]=4,num[3]=5;这     样转化后并不影响原来数据的相对大小关系,何乐而不为呢!!!

           还有一点值得注意,当有数据0出现时,由于0&0=0,无法更新,此时我们可以采取加一个数的方法将所有的数据都变成大于0的。

          下面看代码:

     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     while(scanf("%d",&n),n)
    32     {
    33         memset(c,0,sizeof(c));
    34         int ans=0;
    35         for(int i=1;i<=n;i++)
    36         {
    37             int a;
    38             scanf("%d",&a);
    39             update(a,1);
    40             ans+=i-get_sum(a);
    41         }
    42         printf("%d
    ",ans);
    43     }
    44     return 0;
    45 }
    View Code
  • 相关阅读:
    删除maven本地库中下载不完全的jar包
    nginx负载均衡
    对字符串中的中英文进行统计
    springboot部分常用注解
    Scala 泛型
    Scala 递归举例
    Kafka(v0.11)笔记
    Scala 匿名函数与参数类型推断(简写)
    Scala 高阶函数
    Scala 偏函数 PartialFunction
  • 原文地址:https://www.cnblogs.com/i-love-acm/p/3251036.html
Copyright © 2020-2023  润新知