poj2299(逆序数+线段树)

Ultra-QuickSort
Time Limit: 7000MS Memory Limit: 65536K
Total Submissions: 34679 Accepted: 12466

Description

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

Source

 
        本题给定一个序列,要求相邻的数交换多少次后可以得到一个递增的序列。这个题的过程似曾相识,仔细想了想,原来是冒泡排序的基本过程思想。冒泡模拟,肯定会超时的,冒泡的时间复杂度为O(N*N)。我们可以这样想,我们先把最大的移到最后,然后是次大的……这样一来就变了了我们熟悉的模型,求该序列的逆序数了。求逆序数是经典的线段树的用法。
         这里说说求逆序数的线段树的做法。先把序列离散化,即从小到大排序,序号与数列中的数对应,然后按序列原有的顺序依次统计每个数的对应的逆序数,并修改线段树。具体做法是先查询线段数中比它大且排在它前面的数,对应区间为当前到末尾的区间和;然后再对应位置插入该数,即将对应位置修改为1.下面使用树状数组实现的:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN=500000+100;
int da[MAXN];
int tda[MAXN];
//**********************************************
int C[MAXN];
int Lowbit[MAXN];
//C[i] = a[i-lowbit(i)+1] + …+ a[i],下表从1开始
//Lowbit[i]=i&(i^(i-1));或Lowbit[i]=i&(-i); 
//1.查询
int QuerySum(int p)
//查询原数组中下标1-p的元素的和 
{ 
   int nSum=0; 
   while(p>0) 
   {  
      nSum+=C[p]; 
      p-=Lowbit[p]; 
   } 
    return nSum; 
} 

//2.修改+初始化
void Modify(int p,int val) 
//原数组中下表为p的元素+val,导致C[]数组中部分元素值的改变
{ 
    while(p<=MAXN-10) 
   { 
      C[p]+=val; 
      p+=Lowbit[p]; 
    } 
} 
//************************************************************

bool cmp(int a,int b)
{
	return a<b;
}

int Binary_research(int tmp,int n)
{
	int mid,low=1,high=n;
	while(low<=high)
	{
		mid=(low+high)>>1;
		if(tda[mid]<=tmp)low=mid+1;
		else high=mid-1;
	}
	return high;
}

int main()
{
	int n,i;
	__int64 ans;
	for(i=1;i<MAXN;i++)
		Lowbit[i]=i&(-i);

	while(~scanf("%d",&n),n)
	{
		for(i=1;i<=n;i++)
		{
			scanf("%d",&da[i]);
			tda[i]=da[i];
		}
		sort(tda+1,tda+n+1,cmp);
		memset(C,0,sizeof(C));

		ans=0;
		for(i=1;i<=n;i++)
		{
			int id=Binary_research(da[i],n);
			ans+=(__int64)(QuerySum(n)-QuerySum(id));
			Modify(id,1);
		}
		printf("%I64d\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值