hihocoder 1926 逆序对计数 (树状数组 推荐)

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

给定一个长度为N的数组A1, A2, ... AN,恰好是1~N的一个排列。请你计算所有连续子数组Al, Al+1, ... Ar的逆序对数目之和是多少。(1 <= l < r <= N)

输入

第一行包含一个整数N。  

第二行包含N个整数,A1, A2, ... AN。恰好是1~N的一个排列。  

对于30%的数据,1 <= N <= 1000  

对于60%的数据,1 <= N <= 10000

对于100%的数据,1 <= N <= 100000

输出

一个整数代表答案。

样例输入

5  
5 1 2 3 4

样例输出

10

题目链接:https://hihocoder.com/problemset/problem/1926

题目分析:考虑每个数字本身对答案的贡献,对于一个数字x,需要得到两个值,一是其之后比其小的数的个数,二是x在原数组中从前往后数的位置,因要求所有连续子数组,故x之后比其小的数的个数需要重复累加,累加的部分恰好是其在原数组中从后往前数的位置,举个例子

a[] = 3 1 5 2 4 

i        ans        b[]

5       0            0 0 0 1 0

4       0            0 2 0 1 0

3       9            0 2 0 1 3

2       9            4 2 0 1 3

1       15          4 2 5 1 3

b[i]指的是数字i在a数组中是从后往前数的第几个,下面说明i=3时ans的9是如何计算出来的:

i=3时,a[i]=5,5之后比其小的数的个数通过树状数组求出来是3,这里的3包括了1组5和4的逆序和2组5和2的逆序,即(524,52,524),5在原数组中从前往后数是第3个,因此ans=3*3=9,这里乘3是为了加上前缀,即

(524,52,524) 

(1524,152,1524)

(31524,3152,31524) 这里的三个只是标记54在31524中存在,52在3152中存在,52在31524中存在,上同

i=5时同理

#include 
#define ll long long
int const MAX = 100005;
int a[MAX], n;
ll c[MAX];

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

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

ll query(int x) {
    ll ans = 0;
    for (int i = x; i > 0; i -= lowbit(i)) {
        ans += c[i];
    }
    return ans;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    ll ans = 0;
    for (ll i = n; i > 0; i--) {
        ans += i * query(a[i] - 1);
        update(a[i], n - i + 1);
    }
    printf("%lld\n", ans);
}

 

你可能感兴趣的:(ACM,数据结构,算法题)