用树状数组求逆序对
分析
树状数组初始化为 0 。我们可以利用树状数组依次将输入的值所对应的位置改为 1。对于第i
个数a[i]
来说,若与其能组成逆序对则比它大的数会在i
前边加入到数组,此时**1~a[i] 的前缀和 **即为小于等于a[i]
的数的数量,则i - sum(a[i])
即为逆序对的数量。
对于此题来说,数组元素范围太大,建树的时候会报数组。但是元素数量较少且我们只需要知道元素间的相对大小即可。所以我们可以对*元素先排序,再进行离散化。*当然,也要记录初始顺序。
总结
- 用树状数组依次将输入的值所对应的位置改为 1。
- 对元素先排序,再进行离散化
i - sum(a[i])
即为逆序对的数量。(sum(a[i])表示1~a[i]的前缀和)
code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
int tr[N], a[N];
int n, m, k, t;
struct node
{
int num, val;
}q[N];
bool cmp(node a, node b)
{
if(a.val == b.val) return a.num < b.num;
return a.val < b.val;
}
int lowbit(int x)
{
return x & -x;
}
void add(int x, int c)
{
for(int i = x; i <= n; i += lowbit(i)) tr[i] += c;
}
int sum(int x)
{
int res = 0;
for(int i = x; i ; i -= lowbit(i)) res += tr[i];
return res;
}
int main()
{
ll ans = 0;
cin >> n;
for(int i = 1; i <= n; i ++)
{
int u;
cin >> u;
q[i].val = u, q[i].num = i;
}
sort(q + 1, q + n + 1, cmp);
for(int i = 1; i <= n; i ++) a[q[i].num] = i;
for(int i = 1; i <= n; i ++)
{
add(a[i], 1);
ans += (i - sum(a[i]));
}
cout << ans << "\n";
return 0;
}