HDU 3473 Minimum Sum

#include<cstdio>
#include<algorithm>
using namespace std;

typedef __int64 lld;
#define M 100005
#define md(x,y) (((x)+(y))>>1)

int sorted[M];

struct node{
	int val[M];// val记录第k层当前位置的元素的值
	int num[M];// num记录元素所在区间的当前位置之前进入左孩子的个数
	lld sum[M];// sum记录比当前元素小的元素的和。当前值为mid,即是进入左区间的元素的和
}t[20];

void build(int lft,int rht,int p){
	if(lft==rht)return ;
	int i,mid=md(lft,rht);
	int isame=mid-lft+1,same=0;
	/* isame用来标记和中间值val_mid 相等的,且分到左孩子的数的个数。
LBoy-2
初始时,假定当前区间[lft,rht]有mid-lft+1个和val_mid 相等。 先踢掉比中间值小的,剩下的就是要插入到左边的*/
	for(i=lft;i<=rht;i++)
		if(t[p].val[i]<sorted[mid])
			isame--;
		int ln=lft,rn=mid+1;
		for(i=lft;i<=rht;i++){
			if(i==lft){
				t[p].num[i]=0;
				t[p].sum[i]=0;
			}else{
				t[p].num[i]=t[p].num[i-1];
				t[p].sum[i]=t[p].sum[i-1];
			}
			if(t[p].val[i]<sorted[mid]){
				t[p].num[i]++;
				t[p].sum[i]+=t[p].val[i];
				t[p+1].val[ln++]=t[p].val[i];
			}else if(t[p].val[i]>sorted[mid]){
				t[p+1].val[rn++]=t[p].val[i];
			}else{
				if(same<isame){
					same++;
					t[p].num[i]++;
					t[p].sum[i]+=t[p].val[i];
					t[p+1].val[ln++]=t[p].val[i];
				}else{
					t[p+1].val[rn++]=t[p].val[i];
				}
			}
		}
	build(lft,mid,p+1);
	build(mid+1,rht,p+1);
}

lld sum;

/*
s 记录区间[a, b]中进入左孩子的元素的个数。 
ss 记录区间[lft, a-1)中计入左孩子的元素的个数。 
sss记录区间[a, b]中小于第k大元素的值的和。 
bb 表示[lft, a-1]中分到右孩子的个数
b2 表示[a, b] 中分到右孩子的个数。

*/
int query(int a,int b,int k,int p,int lft,int rht){
	if(lft==rht)return t[p].val[a];
	int s,ss,b2,bb,mid=md(lft,rht);
	lld sss;
	if(a==lft){
		s=t[p].num[b];
		ss=0;
		sss=t[p].sum[b];
	}else{
		s=t[p].num[b]-t[p].num[a-1];
		ss=t[p].num[a-1];
		sss=t[p].sum[b]-t[p].sum[a-1];
	}

	if(s>=k){
		a=lft+ss;
		b=lft+ss+s-1;
		return query(a,b,k,p+1,lft,mid);
	}else{
		bb=a-lft-ss;
		b2=b-a+1-s;
		a=mid+bb+1;
		b=mid+bb+b2;
		sum+=sss;
		return query(a,b,k-s,p+1,mid+1,rht);
	}
}

lld tot[M];

int main(){
	int T,Q,n;
	int a,b;
	int i,j;
	scanf("%d",&T);
	for(int cas=1;cas<=T;cas++){
		scanf("%d",&n);
		for(i=1;i<=n;i++){
			scanf("%d",&sorted[i]);
			tot[i]=tot[i-1]+sorted[i];
			t[0].val[i]=sorted[i];
		}
		sort(sorted+1,sorted+n+1);
		build(1,n,0);
		scanf("%d",&Q);
		printf("Case #%d:\n",cas);
		while(Q--){
			scanf("%d%d",&a,&b);
			a++;b++;
			int k=(b-a+1)/2+1;
			sum=0;
			lld ret=query(a,b,k,0,1,n);
			lld ans=ret*(k-1)-sum;
			ans+=(tot[b]-tot[a-1]-sum)-ret*(b-a+2-k);
			printf("%I64d\n",ans);
		}
		puts("");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值