逆序对问题 | ||||||
| ||||||
Description | ||||||
给定 n 个数组成的数组,求其逆序对的总数。 逆序对定义为,存在 (i, j) 满足 i < j 且 A[i] > A[j] 的二元组的数目。 | ||||||
Input | ||||||
第一行包含一个整数,表示数组的项数。 接下来的一行,包含 n 个数(2 <= n <= 100000),依次表示 A[i](A[i] <= 10^9)。 | ||||||
Output | ||||||
输出一行表示对应的答案。。 | ||||||
Sample Input | ||||||
5 1 3 2 5 4 | ||||||
Sample Output | ||||||
2 | ||||||
Source | ||||||
"诚德软件杯"哈尔滨理工大学第四届ACM程序设计团队赛 |
数据范围很大,暴力一定会超时,使用树状数组动态改变逆序对的值、数据范围到10^9,但是n的范围是10^5、直接开树的数组开不到10^9,所以需要离散化、
关于离散化:
假设我们这里一组数据:
2
3 2
sort之后为:
2 3
对应原来的位子是2 1,然后我们对应sort的顺序从大到小赋值,把2变成1,把3变成2,原先不变的成分是位子,我们保留原来的位子就能做到离散化了
关于最终求逆序对:
我们把离散化后的数据每次都入树,同时统计之前入树的有多少个元素比他大,加和即可。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
struct zuobiao
{
int date,pos;
}a[121212];
int tree[1000005];
int aa[121212];
int n;
int lowbit(int x)
{
return x&(-x);
}
int sum(int x)
int sum=0;
while(x>0)
{
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
void add(int x,int c)//加数据。
{
while(x<=n)
{
tree[x]+=c;
x+=lowbit(x);
}
}
int cmp(zuobiao a,zuobiao b)
{
if(a.date==b.date)
return a.pos<b.pos;
else
return a.date<b.date;
}
int main()
{
while(~scanf("%d",&n))
{
if(n==0)break;
memset(tree,0,sizeof(tree));
long long int output=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].date);
a[i].pos=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
aa[a[i].pos]=i;
}
for(int i=1;i<=n;i++)
{
add(aa[i],1);
output+=(i-sum(aa[i]));
}
printf("%lld\n",output);
}
}