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

    对于数的范围比较小,我们可以这样来求解逆序对。

    树状数组b[val]表示的是val在数组中出现的次数。

    我们倒序扫描原数组a,对于位置i,由于树状数组里面保存的是val出现的次数,我们先用树状数组求出当前树状数组中比a[i]这个值小的元素的个数,由于是倒序扫描,之前加入树状数组中的数的位置都在i后面,因此我们就把求得的比a[i]这个值小的元素的个数累加到答案中。

    for(int i=n;i;i--)
    {
         ans+=ask(a[i]-1);  
         add(a[i],1);  
    }

    这是针对数的范围较小采取的方法,当数的范围较大时,我们对数据经行排序,然后离散化。下面给出一种求解方法。

    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int N = 5e5 + 10;
    typedef long long ll;
    #define lowbit(x) (x&(-x))
    int n, m, c[N], a[N], b[N];
    void add(int x)
    {
        for (; x <= n; x += lowbit(x))
            c[x]++;
    }
     int ask(int x)
    {
        int s = 0;
        for (; x > 0; x -= lowbit(x))
            //cout << x <<" "<< c[x] << endl;
            s += c[x];
        return s;
    }
    bool cmp1(const int x, const int y)
    {
        if (b[x] == b[y]) return x > y;//这个要注意,一定要让大的跑前面,不然就会多统计
        return b[x]>b[y];
    }
    int main()
    {
        scanf("%d", &n);
        ll ans = 0;
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &b[i]);
            a[i] = i;
        }
        sort(a + 1, a + n + 1, cmp1);
        for (int i = 1; i <= n; i++)
        {
            add(a[i]);
            ans += 1LL * ask(a[i] - 1);//之前加入数状数组的元素都比当前元素值大,因此我们查询下标比当前小的个数,累加答案
        }
        printf("%lld
    ", ans);
        return 0;
    }

    这种情况需要先排序,那还不如直接用归并排序求。

  • 相关阅读:
    设计模式学习笔记-观察者模式
    谈C#中的Delegate
    EF 增删改查 泛型方法、类
    什么是表达式树,它与表达式、委托有什么区别?
    查询出各个学科的前3名的同学信息的Sql
    row_number() OVER(PARTITION BY)函数介绍
    Asp.net WebApi 项目示例(增删改查)
    ASP.NET WebAPI从入门
    .net中的Queue和Stack
    Replication--数据库镜像阻塞复制日志读取器的解决的办法
  • 原文地址:https://www.cnblogs.com/xiaoguapi/p/10543797.html
Copyright © 2011-2022 走看看