求逆序对----归并排序 或 树状数组+离散化

例题

「POJ2299」Ultra-QuickSort
请分析,对于一串数列,至少要交换多少次(相邻两个数交换)才能使该数列有序(从小到大)?

注意:思考下,当存在两个数相等时,应该如何处理

输入
第一行:一个整数n<500000——序列的长度;

以下n行每行包括一个整数 0 ≤ a[i] ≤ 999,999,999.

输出
一个整数表示要交换的次数

样例输入
5
9
1
0
5
4
样例输出
6

分析

求逆序对,显然用归并排序。
当然,更好的方法是树状数组。但是a[i]太大,所以需要离散化。

代码

归并排序

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define full(a,b,c) fill(b,b+sizeof a/4,c)
#define N 500000+5
int n,arr[N];
int c[N];
long long ans;
void msort(int left,int right)
{
	if(left==right)return;
	int mid=(left+right)>>1;
	msort(left,mid);
	msort(mid+1,right);
	int i=left,j=mid+1,k=left;
	while(i<=mid&&j<=right)
		if(arr[i]<=arr[j])//!!! if是<=,else则是> 
			c[k++]=arr[i++];
		else c[k++]=arr[j++],ans+=(long long)mid-i+1;//第i个数比后面mid-i+1都小 
	while(i<=mid)c[k++]=arr[i++];
	while(j<=right)c[k++]=arr[j++];
	for(int i=left; i<=right; i++)arr[i]=c[i];
}
int main()
{
	scanf("%d",&n);
	for(int i=1; i<=n; i++)
		scanf("%d",&arr[i]);
	msort(1,n);
	printf("%lld",ans);	
}

树状数组+离散化

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define full(a,b) memset(a,b,sizeof a)
#define N 500000+5
#define lowbit(x) x&(-x)
struct node{
	int s,t;
}arr[N];
int n,tree[N],za[N];
long long ans;
bool cmp(node x,node y)
{return x.s<y.s;}
void update(int x,int y){
	for(int i=x;i<=N;i+=lowbit(i))
	tree[i]+=y;
}
int sum(int x){
	int ret=0;
	for(int i=x;i>0;i-=lowbit(i))
	ret+=tree[i];
	return ret;
}//常规套路 
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&arr[i].s);//输入原值 
		arr[i].t=i;//原位置 
	}
	sort(arr+1,arr+1+n,cmp);//按从小到大排序 
	arr[0].s=-1;//方便后面循环 
	for(int i=1;i<=n;i++){
		za[arr[i].t]=i;//原位置为t,新位置为i 
		if(arr[i].s==arr[i-1].s)//与前一个数值相等 
		za[arr[i].t]=za[arr[i-1].t];
	}
	for(int i=n;i>=1;i--){//逆序,保证只会找后面的数 
		ans+=1LL*sum(za[i]-1);//找比i小的 
		update(za[i],1);
	}
	printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值