POJ2266——Ultra-QuickSort

原题题址
其实嘛,这个求冒泡排序的次数的问题,好像叫啥逆序对,我不是很了解啊。我就知道,最小次数就是每个数最小交换次数的和,每个数最小交换次数就是找出是每个数前面有几个大于他的数就结了么。
晓得了这个,介个问题嘛,就按想法整,从前往后找,找在当前数前面有几个大于它的数。虽然是权值线段树的活,但是由于某些原因,我们就用树状数组搞定它。
那咋整呢?
首先,把序列排序(便于单点修改,要是线段树就不需要),按照原序列顺序插入到树状数组中,实际上是对应位置+1,查询区间[1,i]的和,即该区间内数的个数,i - sum(i)就是比a[i]大的数的个数。
代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std; 

const int maxn = 5e5+5;
typedef long long ll; 
int N,a[maxn],disc[maxn],sum[maxn];

int lowbit(int x){
	return x&-x;
}

void Updata(int p,int v){
	while(p <= N){
		sum[p]+=v;
		p+=lowbit(p);
	}
}

ll Query(int p){
	int ans = 0;
	while(p){
	   ans+=sum[p];
	   p-=lowbit(p);	
	}
	return ans;
}
int main(){
	while(~scanf("%d",&N)){
		if(N==0)break;
		memset(sum,0,sizeof(sum));
		for(int i = 1;i <= N;i++){
			scanf("%d",&a[i]);
			disc[i] = a[i];
		}
		 sort(disc + 1,disc + 1 + N);
		 ll ans = 0;
	    for(int i = 1;i <= N;i++){
	    	int tmp = lower_bound(disc + 1,disc + 1 + N,a[i]) - disc;
	    	Updata(tmp,1);
	       ans += i -  Query(tmp);
	    
		}	
			printf("%lld\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值