luogu1908 逆序对 树状数组

题目大意:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。求一段序列的逆序对数。

对于一个数组T,其一个点的值为值与该点下标相等的A序列中点的个数。对T维护一个树状数组C。对原始序列A,从后往前扫描i,每次运用树状数组的求前缀和操作查询比A[i]小的数字有几个(因为是倒序循环,所以得到的数字所对应的A序列中的点j都是大于i的)(*),然后运用树状数组的更新操作将树状数组点T[A[i]]的值加1。最后输出(*)的总和。

注意事项:

  • 由于树状数组是在值域上建立的,所以N是输入值的最大值,而不是个数。
  • Query a[i]时,Query(a[i]-1),而不是Query(a[i])。否则两个值相等也被算上了。
#include <cstdio>
#include <cstring>
#include <cassert>
#include <cmath>
#include <algorithm>
using namespace std;

const int MAX_N = 40010, MAX_VALUE = 1000000, INF = 0x3f3f3f3f;
int C[MAX_VALUE], A[MAX_N];
int totN, totValue;

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

int Sum(int p)
{
    int sum = 0;
    while (p)
    {
        sum += C[p];
        p -= Lowbit(p);
    }
    return sum;
}

void Update(int p, int delta)
{
    while (p <= totValue)
    {
        C[p] += delta;
        p += Lowbit(p);
    }
}

int main()
{
    totValue = -INF;
    scanf("%d", &totN);
    for (int i = 1; i <= totN; i++)
    {
        scanf("%d", i + A);
        totValue = max(totValue, A[i]);
    }
    int ans = 0;
    for (int i = totN; i >= 1; i--)
    {
        ans += Sum(A[i] - 1);
        Update(A[i], 1);
    }
    printf("%d\n", ans);
    return 0;
}

  

posted @ 2018-02-14 12:00  headboy2002  阅读(153)  评论(0编辑  收藏  举报