Description
__M子__最近在学习线性代数,用的是厦门理工学院自己出的书,第一节课介绍了逆序数的概念。
课本第一页:
定义2 在一个排列中,如果两个数(不一定相邻)的前后位置与标准排列的前后位置不同,即前面的数大于后面的数,则称它们构成一个逆序,一个排列中所有逆序的个数称为这个排列的逆序数。
例如 2431中,21,41,31,43是全部逆序,它的逆序数就是4。
第一次作业布置了很多求逆序数的题目,__M子__这个人很懒,觉得求逆序数每次都手算太麻烦,想编一个程序来解决。
Input
输入数据第一行是一个整数T。下面由T组测试数据组成,对于每一个测试:
第一行包含两个整数n(1 <= n <= 10^5)。第二行包含n个整数A1,A2,…,同比(0 <= Ai <= 10^9)。
Output
对于每一个测试数据,输出一行,每行有一个整数表示逆序数。
Sample Input
2
4
2 4 3 1
4
3 3 3 1
Sample Output
4
3
这题可以用归并排序的思想、线段树、树状数组等方法做。正好硬盘里有线段树模板,就拿来稍加修改交了。
由于数据范围过大,建树前得先对数据进行离散化处理。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Node
{
long long val;
int pos;
bool operator<(const Node& temp) const
{
return val < temp.val;
}
};
long long query(vector<long long>& tree, int root, int L, int R, int l, int r);
void insert(vector<long long>& tree, int root, int val, int l, int r);
int main(void)
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
vector<Node> nums(n);
for (int i = 0; i < n; ++i)
{
cin >> nums[i].val;
nums[i].pos = i;
}
sort(nums.begin(), nums.end());
int cnt = 0;
vector<int> arr(n);
for (int i = 0; i < n; ++i)
if (i && nums[i].val == nums[i - 1].val)
arr[nums[i].pos] = cnt - 1;
else
arr[nums[i].pos] = cnt++;
long long ans = 0;
vector<long long> tree(n * 4, 0);
for (int i = n - 1; i >= 0; --i)
{
ans += query(tree, 0, 0, arr[i] - 1, 0, n - 1);
insert(tree, 0, arr[i], 0, n - 1);
}
cout << ans << endl;
}
}
long long query(vector<long long>& tree, int root, int L, int R, int l, int r)
{
if (L == l && R == r)
return tree[root];
else if (R < l)
return 0;
else
{
long long sum = 0;
int mid = (l + r) >> 1;
if (L <= mid)
sum += query(tree, root * 2 + 1, L, min(mid, R), l, mid);
if (R > mid)
sum += query(tree, root * 2 + 2, max(mid + 1, L), R, mid + 1, r);
return sum;
}
}
void insert(vector<long long>& tree, int root, int val, int l, int r)
{
if (l != r)
{
int mid = (l + r) >> 1;
if (val <= mid)
insert(tree, root * 2 + 1, val, l, mid);
else
insert(tree, root * 2 + 2, val, mid + 1, r);
}
++tree[root];
}