逆序对(树状数组)

链接:https://www.nowcoder.com/acm/contest/77/A
来源:牛客网

逆序数
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。比如一个序列为4 5 1 3 2, 那么这个序列的逆序数为7,逆序对分别为(4, 1), (4, 3), (4, 2), (5, 1), (5, 3), (5, 2),(3, 2)。

输入描述:

第一行有一个整数n(1 <= n <= 100000),  然后第二行跟着n个整数,对于第i个数a[i],(0 <= a[i] <= 100000)。

输出描述:

输出这个序列中的逆序数
示例1

输入

5
4 5 1 3 2

输出

7
先离散化,得到数组b[i],
a:88 11 62 5 23
b:5  2  4  1 3
i为1,那么在5的位置+1,
即 1 2 3 4 5
sum[i] 0 0 0 0 1

在计算5及5之前有几个数,为1个数,再用总数-1=4,代表和5组成逆序对的有4个数。
 1 #include <iostream>
 2 #include <cstring>
 3 #include <string>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 int T, n;
 8 int sum[100005];
 9 
10 struct node
11 {
12     int pos, x;
13 }a[100005];
14 int b[100005];
15 
16 bool cmp(node x, node y)
17 {
18     return x.x < y.x;
19 }
20 
21 void update(int pos, int val)
22 {
23     while (pos <= n)
24     {
25         sum[pos] += val;
26         pos += (pos&(-pos));//加上最末尾的1所代表的个数,12,1100,+4+8
27     }
28 }
29 
30 int query(int pos)
31 {
32     int rec = 0;//13为1101,减去末尾的1(1),1100,再减去末尾的1(4),1000,再减(8),000
33     while (pos > 0)
34     {
35         rec+=sum[pos];
36         pos -= (pos&(-pos));
37     }
38     return rec;
39 }
40 
41 int main()
42 {
43     long long nxs = 0;
44     cin >> n;
45     memset(sum, 0, sizeof(sum));
46     for (int i = 1,x; i <= n; i++)
47     {
48         cin >> a[i].x;
49         a[i].pos = i;//记录原先的位置,88 11 62 5 23
50     }
51     sort(a + 1, a + n + 1, cmp);
52     for (int i = 1; i <= n; i++)
53     {
54         b[a[i].pos] = i;//5原来在4的位置b【4】=1
55         //a:88 11 62 5 23
56         //b:5  2  4  1 3
57     }
58     /*for (int i = 1; i <= n; i++)
59     {
60         cout << b[i] << " ";
61     }
62     cout << endl;*/
63     for (int i = 1; i <= n; i++)
64     {
65         update(b[i], 1);
66         int temp = query(b[i]);
67         nxs += b[i] - temp;
68     }
69     cout << nxs << endl;
70 }
原文地址:https://www.cnblogs.com/caiyishuai/p/13271167.html