• 树状数组 P1908 逆序对


    题目

    https://www.luogu.com.cn/problem/P1908

    题目分析

    树状数组的使用原因

    可以开一个数组c[maxn],来记录前面数据的出现情况,初始化为0;当数据a出现时,就令c[a]=1。这样的话,欲求某个数a的逆序数,只需要算出在当前状态下c[a+1,maxn]中有多少个1,因为这些位置的数在a之前出现且比a大。这其实就是明显的单点更新(数据a出现时,就令c[a]=1),区间查询(c[a+1,maxn]中有多少个1)——树状数组
    而getsum(c[a+1,maxn])等价于 i - getsum( c[i] ),其中 i 为当前已经插入的数的个数 getsum( c[i] )为比 c[i] 小的数的个数,i- getsum( c[i] ) 即比c[i] 大的个数, 即逆序的个数。
    最后需要把所有逆序数求和,就是在插入的过程中边插入边求和.

    离散化原理

    输入:9 -1 18 5

    输出 3.

    输入之后对应的结构体就会变成这样

    val:9 -1 18 5

    id:  1  2  3  4

    排好序之后就变成了

    val :  -1 5 9 18

    id:      2 4  1  3

    2 4 1 3 的逆序数 也是3

    这样原来是输入9,就把t[9]置为1,输入18,就把t[18]置为1,最后遍历t数组到输入数字的最大值,统计出现过的次数,如果输入一个1000000,就要遍历t数组到t【1000000】

    现在使用id等价代替原数组,只需要输入元素个数的空间即可,节省了数组空间

    相等元素处理

    如果遇到相等的元素,就使用id(即输入的顺序)区分,这样后输入的相等元素的id大,在进行id等价转换的时候它的转换情况偏小(自己的id大了,转换后相对于自己的数大了,那么找自己前面比自己大的数就有可能结果偏小),但是前面还有一个与自己数字相等的元素,它的id是准确的,也就是最后不会影响结果

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    struct node
    {
        long long val;
        int id;
    }a[500005];
    long long c[500005];
    int n;
    bool cmp(struct node &a, struct node&b)
    {
        if (a.val == b.val)return a.id < b.id;
        return a.val < b.val;
    }
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int i, int k)
    {
        while (i <= n)
        {
            c[i] += k;
            i += lowbit(i);
        }
    }
    long long getsum(int i)
    {
        long long res = 0;
        while (i > 0)
        {
            res += c[i];
            i -= lowbit(i);
        }
        return res;
    }
    int main()
    {
        int aa, bb, cc,dd;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
        {
            scanf("%lld", &a[i].val);
            a[i].id = i;
        }
        sort(a + 1, a + n + 1, cmp);
        long long answer = 0;
        for (int i = 1; i <= n; i++)
        {
            update(a[i].id,1);
            answer += i - getsum(a[i].id);//用来存储原数第i个数的order下标是什么
        }
        printf("%lld
    ", answer);
    }

    参考:https://www.jianshu.com/p/8a4081f0ec20

    https://blog.csdn.net/m0_38033475/article/details/80330157

  • 相关阅读:
    数据库:常用的类库、对应的方法和属性
    robotframe常用的类库、对应的方法和属性
    appium常用的类库、对应的方法和属性
    selenium常用的类库、对应的方法和属性
    Python常用的类库、对应的方法和属性
    Python MySQLdb中执行SQL语句传入的参数应该要加上引号如果该字段是str类型的
    接口测试,如何构建json类型的参数值
    使用pip install mysqlclient命令安装mysqlclient失败?(基于Python)
    如何切换虚拟机(centos6)和windows
    ZOJ
  • 原文地址:https://www.cnblogs.com/Jason66661010/p/12827953.html
Copyright © 2020-2023  润新知