hdu 1394 最小逆序数(线段树版本)

    从该数字num[i]就可以知道比它小的数有num[i]个,比它大的数有n-1-num[i]个.

         每次把num[i]放到最后时,summ = summ – num[i] + n-1-num[i];

#include<cstdio>

#define Min(a,b) (a)<(b)?(a):(b)
#define M 5005
#define mid (l+r)>>1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

int sum[M<<2];

void PushPlus(int rt){
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void Updata(int p,int l,int r,int rt){

	if( l == r){
		sum[rt]++;
		return ;
	}

	int m=mid;
	if(p<=m)
		Updata(p,lson);
	else
		Updata(p,rson);

	PushPlus(rt);

}

void Bulid(int l,int r,int rt){

	sum[rt]=0;

	if(l == r)
		return ;

	int m=mid;

		Bulid(lson);
		Bulid(rson);
//	PushPlus(rt);反正都是0
}

int Query(int L,int R,int l,int r,int rt){

	if(L <= l && r <=R)
		return sum[rt];
	
	int m=mid,ans=0;
	if(L<=m)
		ans+=Query(L,R,lson);
	if(R>m)
		ans+=Query(L,R,rson);
	return ans;
}

int num[M];

int main(){

	int n;

	while(~scanf("%d",&n)){
		Bulid(0,n-1,1);
		int summ=0;
		for(int i=0;i<n;i++){
			scanf("%d",&num[i]);
			summ+=Query(num[i],n-1,0,n-1,1);

			Updata(num[i],0,n-1,1);
		}
		int minsum=summ;
		for(int j=0;j<n;j++){
			summ+=n-num[j]-num[j]-1;

			minsum=Min(summ,minsum);
		}
		printf("%d\n",minsum);
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值