hdu 3473 区间条件极值

题目传送门//res tp hdu

目的

对长度为n的区间,给定q个子区间,求一x,使得区间内所有元素与x的差的绝对值之和最小。
多测。
n 1e5
q 1e5
ai [1,1e9] (i∈[1,n]);

数据结构

划分树

tip

该划分树维护的cnt并非元素所在区间内,该元素之前进入左子树的元素个数,而是整个区间内,该元素之前进入左子树的元素个数。

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

const int L = 100000+50;
typedef long long ll;
int n,q;
int tree[18][L];
int cnt[18][L];
ll sum[18][L],ans;
int a[L],sorted[L];

void build(int de,int l,int r){
	if(l == r){
		sum[de][l] = sum[de][l-1] + tree[de][l];return;
	}
	if(de == 0){
		for(int i = 1;i<=r;++i)
			tree[de][i] = a[i];
	}
	int mi=(l+r)>>1;
	int scnt = mi - l + 1;
	ll M = sorted[mi];
	for(int i = l;i<=mi;++i) if(sorted[i] < M)
		scnt--;
	int pl = l,pr = mi + 1;
	for(int i = l;i<=r;++i){
		ll num =tree[de][i];
		if(num == M){
			if(scnt){
				scnt--;
				tree[de+1][pl++] = num;
				cnt[de][i]++;
			}
			else
				tree[de+1][pr++] = num;
		}
		else if(num < M){
			tree[de+1][pl++] = num;
  			cnt[de][i]++;
		}
		else
			tree[de+1][pr++] = num;
		sum[de][i] = sum[de][i-1] + tree[de][i];
		cnt[de][i] += cnt[de][i-1];
	}
	build(de+1,l,mi);
	build(de+1,mi+1,r);
}

ll query(int de,int L,int R,int l,int r,int k){
	if(L == R) return tree[de][L];

	int mi = (L + R)>>1;
	int lo1,lo2,hi1,hi2;
	int CNT = cnt[de][r] - cnt[de][l-1];
	lo1 = L + cnt[de][l-1] - cnt[de][L-1];
	hi1 = L + cnt[de][r] - cnt[de][L-1] - 1;
	lo2 = mi + 1 + l - L - cnt[de][l-1] + cnt[de][L-1];
	hi2 = mi + 1 + r - L - cnt[de][r] + cnt[de][L-1];
	if(k <= CNT){
		if(hi2 >= lo2)
			ans += sum[de+1][hi2] - sum[de+1][lo2-1];
		return query(de+1,L,mi,lo1,hi1,k);
	}
	else{
		if(hi1>=lo1)
		ans -= sum[de+1][hi1] - sum[de+1][lo1-1];
		return query(de+1,mi+1,R,lo2,hi2, k - CNT);
	}
}




int main(){
	int T,l,r;
	int icase = 1;
	scanf(" %d",&T);
	while(T--){
		scanf(" %d",&n);
		memset(sum,0,sizeof(sum));
		memset(cnt,0,sizeof(cnt));
		for(int i = 1;i<=n;++i){
			scanf(" %d",a + i);
			sorted[i] = a[i];
		}
		sort(sorted+1,sorted+1+n);
		build(0,1,n);
		scanf(" %d",&q);
		printf("Case #%d:
",icase++);
		while(q--){
			ans = 0;
			scanf(" %d %d",&l,&r);
			l++;r++;
			ll t = query(0,1,n,l,r,(r - l)/2 + 1);
			if((r-l)%2 == 1)
				ans -= t;
			printf("%lld
", ans);
		}
		cout<<endl;
	}
}


原文地址:https://www.cnblogs.com/tea-egg/p/11247723.html