Description
Ultra-QuickSort produces the output
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
Input
The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.
Output
For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.
Sample Input
5 9 1 0 5 4 3 1 2 3 0
Sample Output
6 0
树状数组入门应用——求逆序数,话说没做这道题以前我根本就不知道树状数组是个什么东西,做完之后,有了一点感觉。
题目意思是说,用冒泡排序交换的方法对一个序列排序,问需要交换多少次。那便是一道求逆序数的题,即,若序列i<j,a[i]>a[j],这样的逆序数是几。
写个结构体保存输入时的位置pos.
然后根据值value排序。
构造一个树状数组,序列里每插入一个元素,树状数组就更新一次,统计当前元素前面有多少个元素比自己小,包括自己,则逆序对数为i-sum(re[i])。
查看它前面比它小的已出现过的有多少个数sum,然后用当前位置减去该sum,就可以得到当前数导致的逆序对数了。把所有的加起来就是最后的答案。
除去上面的收获,还接触到了离散化这种方法。
因为题目中0 ≤ a[i] ≤ 999,999,999 n < 500,000 ,内存有限制。这时候就需要离散化登场了。
把原始的数映射为1-n一共n个数,这样就只需要500000个int类型的空间。
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define N 500005
using namespace std;
typedef struct{
int key,value;
}Node;
Node a[N];
int c[N];
int re[N];
int n;
int lowbit(int x)
{
return x&-x;
}
int sum(int x)
{
int ret=0;
while(x>0)
ret+=c[x],x-=lowbit(x);
return ret;
}
void add(int x,int d)
{
while(x<=n)
{
c[x]+=d;x+=lowbit(x);
}
}
bool cmp(Node a,Node b)
{
return a.value<b.value;
}
int main()
{
while(scanf("%d",&n)>0&&n)
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i].value),a[i].key=i;
sort(a+1,a+n+1,cmp);
for (int i = 1; i <= n; i++)
re[a[i].key] = i;
memset(c,0,sizeof(c));
long long ans = 0;
for (int i = 1; i <= n; i++)
{
add(re[i],1);
ans += i - sum(re[i]);
}
printf("%I64d\n", ans);
}
return 0;
}