码迷,mamicode.com
首页 > 编程语言 > 详细

树状数组求逆序对

时间:2019-03-16 19:15:01      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:col   数组   cst   出现   +=   end   mes   范围   define   

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

树状数组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\n", ans);
    return 0;
}

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

树状数组求逆序对

标签:col   数组   cst   出现   +=   end   mes   范围   define   

原文地址:https://www.cnblogs.com/xiaoguapi/p/10543797.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!