洛谷题单指南-二叉堆与树状数组-P1908 逆序对

原题链接:https://www.luogu.com.cn/problem/P1908

题意解读:求逆序对,前面介绍过归并排序的做法,参考:https://www.cnblogs.com/jcwy/p/184077,这里介绍树状数组的做法。

解题思路:

设数组a[n]里的整数只包括1~n,显然对于此题,可以通过离散化得到这样的数组。

要计算逆序对,就是要计算对于每一个数,位置靠后且值较小的数有多少个,累加起来即可。

如何统计比每一个数位置靠后且值较小的数的个数?

设b[i]表示值为i的数出现的个数,

可以从后往前遍历a中每一个数,对于每一个遍历到的数a[i],计算b[1] ~ b[a[i] - 1]之和,累加到ans,

然后把a[i]的个数更新b[a[i]]++,如此便可以统计所有的逆序对数量。

问题转化为如何快速计算b的前缀和,以及修改b的值,此时就可以借助树状数组!

设树状数组tr[N]是b的树状数组,通过sum(a[i] - 1)来计算b[1] ~ b[a[i] - 1]之和,通过add(a[i], 1)来实现b[a[i]]++。

100分代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 500005;
int n;
int a[N], b[N], c[N], cnt, tr[N];
map<int, int> h;
LL ans;

int lowbit(int x)
{
    return x & -x;
}

void add(int x, int val)
{
    for(int i = x; i <= n; i += lowbit(i)) tr[i] += val;
}

int sum(int x)
{
    int res = 0;
    for(int i = x; i; i -= lowbit(i)) res += tr[i];
    return res;
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    //去重,离散化
    memcpy(b, a, sizeof(a));
    sort(b + 1, b + n + 1);
    for(int i = 1; i <= n; i++)
    {
        if(b[i] != b[i - 1]) c[++cnt] = b[i], h[c[cnt]] = cnt;
    }
    for(int i = 1; i <= n; i++) a[i] = h[a[i]];

    //逆序对统计
    for(int i = n; i >= 1; i--)
    {
        ans += sum(a[i] - 1);
        add(a[i], 1);
    }
    cout << ans;

    return 0;
}

 

posted @   五月江城  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示