数状数组 及其在 求逆序对中的应用

讲解链接


如果树状数组维护的是a数组的值,那么 sum[i] 表示在 a 数列1~i中的元素的和
查询(l,r)中元素的和就为 sum(r)-sum(l)


逆序对的定义: i < j && a[i] > a[j]
例题中的逆序对: pre[i]为1~i中a[i]的个数; nex[i]为i~n中a[i]的个数
这时候的逆序对就是,i < j && pre[i] > nex[j]
注意求法,很神奇


题目链接:

#include<iostream>
#include <cstdio>
#include <map>
using namespace std;
typedef long long ll;
const int maxn = 1000017;
int n;
int a[maxn], c[maxn];
int nex[maxn], pre[maxn];
ll res;
map <int, int> freq;
int Lowbit(int x) //2^k
{
    return x&(-x);
}

void update(int i, int x)//i点增量为x
{
    while (i <= n)
    {
        c[i] += x;
        i += Lowbit(i);
    }
}
int sum(int x)//区间求和 [1,x]
{
    int sum = 0;
    while (x > 0)
    {
        sum += c[x];
        x -= Lowbit(x);
    }
    return sum;
}

int main() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    //pre[i]为1~i中a[i]的个数
    //nex[i]为i~n中a[i]的个数
    for (int i = 0; i < n; i++) {
        pre[i] = ++freq[a[i]];
    }
    freq.clear();
    for (int i = n - 1; i > 0; i--) {
        nex[i] = ++freq[a[i]];
    }
    for (int i = 0; i < n; i++) {
        //这两步可以说是很精妙了,首先当插入i之后,我们query的时候i的坐标已经+1了
        //这时候我们查询序列中有多少个数比nex[i]大其实就是查询数组中有多少个数比nex[i]大
        //一个数组的话就是update谁,就查询谁
        res += i - sum(nex[i]);
        update(pre[i], 1);
    }
    cout << res << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/romaLzhih/p/9489807.html