2299:Ultra-QuickSort(线段树求逆序对)

题目:

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence

9 1 0 5 4 ,


Ultra-QuickSort produces the output

0 1 4 5 9 .


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

先来简单翻译一下题意:就是给你一串数,让你求这串数中逆序对的个数,注意是多组输入.

分析:先举个例子说一下什么是逆序对吧

比如说    9    1    0    5    4

我们可以看每一位的数字的前面有几位比他大的,然后把这些数字加起来就好

9前面没有比他大的,1前面有1个比他大的,0前面有两个比他大的,5前面有1个比他大的,而4前面有两个比他大的.所以这串数字的逆序对就是1+2+1+2=6个,那我们如何通过树状数组来解决这个问题呢?

我们先画一个数轴,我们把这些数字按照从左到右的顺序依次加入到数轴上,比如第一个数字是9,我们就在9的位置上加1,依次类推,假如我们当前恰好加入了第i个数,那么当前数轴上出现的数一定是这串数字的前i个数,我们只要在ans中加入当前数轴上比第i个数大的数字出现的个数就好,画个图就很容易理解了,(注意这道题目需要离散化)下面是代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const int N= 3e6+10;
int l[N],r[N];
long long sum[N];
vector<int> alls;//离散化数组 
int a[N];
int find(int x)
{
	return (lower_bound(alls.begin(),alls.end(),x)-alls.begin()+1);
}
void pushup(int id)
{
	sum[id]=sum[id<<1]+sum[id<<1|1];
}
void build(int id,int L,int R)
{
	l[id]=L;r[id]=R;sum[id]=0;
	if(L==R) return ;
	int mid=L+R>>1;
	build(id<<1,L,mid);
	build(id<<1|1,mid+1,R);
	pushup(id); 
}
void update_point(int x,int id,int val)
{
	if(l[id]==r[id])
	{
		sum[id]+=val;
		return ;
	}
	int mid=l[id]+r[id]>>1;
	if(x<=mid) update_point(x,id<<1,val);
	else update_point(x,id<<1|1,val);
	pushup(id);
}
int query_interval(int id,int L,int R)
{
	if(l[id]>R||r[id]<L) return 0;
	if(l[id]>=L&&r[id]<=R) return sum[id];
	return query_interval(id<<1,L,R)+query_interval(id<<1|1,L,R);
}
int main()
{
	int n,t;
	while(cin>>n)
	{
		if(n==0) break;
		alls.clear();
		build(1,1,n);
		long long ans=0;
		for(int i=1;i<=n;i++)
			{
				scanf("%d",&a[i]);
				alls.push_back(a[i]);
			}
		sort(alls.begin(),alls.end());//排序 
		alls.erase(unique(alls.begin(),alls.end()),alls.end());//去重 
		for(int i=1;i<=n;i++)
		{
			update_point(find(a[i]),1,1);
			ans+=i-query_interval(1,1,find(a[i]));
		}
		printf("%lld\n",ans);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值