HDU 3473

分析可知,最优的x应该在区间中的数排列后最中间的地方选择。由于区间的数个数有奇偶之分,于是当奇数个时,就是中位数了。偶数个时,就是排列后中间两数区间的任意一个。

可以应用划分树求得前半部分,树状数组统计。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL __int64
#define lowbit(x) (x&(-x))
using namespace std;

const int N=100050;
int sorted[N],n,m;
struct node{
    int val[N];
    int num[N];
    LL sum[N];
}tp[20];
LL ANS;
LL arrayTree[N];

void build(int lft,int rht,int p){
    if(lft==rht) return ;
    int i,mid=(lft+rht)/2;
    int isame=mid-lft+1,same=0;
    for(i=lft;i<=rht;i++){
        if(tp[p].val[i]<sorted[mid]) isame--;
    }
    int ln=lft,rn=mid+1;
    for(i = lft; i <= rht; i++) {
        if(i == lft) {
            tp[p].num[i] = 0;
            tp[p].sum[i]=0;
        } else {
            tp[p].num[i] = tp[p].num[i-1];
            tp[p].sum[i]=tp[p].sum[i-1];
        }
        if(tp[p].val[i] < sorted[mid]) {
            tp[p].num[i]++;
            tp[p].sum[i]+=tp[p].val[i];
            tp[p+1].val[ln++] = tp[p].val[i];
        }else if(tp[p].val[i] > sorted[mid]) {
            tp[p+1].val[rn++] = tp[p].val[i];
        }else {
            if(same < isame) {
                same++;
                tp[p].num[i]++;
                tp[p].sum[i]+=tp[p].val[i];
                tp[p+1].val[ln++] = tp[p].val[i];
            }else {
                tp[p+1].val[rn++] = tp[p].val[i];
            }
        }
    }
    build(lft, mid, p+1);
    build(mid+1, rht, p+1);
}

int query(int a, int b, int k, int p, int lft, int rht) {
    if(lft == rht) {
    	return tp[p].val[a];
    }
    LL sss=0;
    int s, ss, b2, bb, mid = (lft+rht)/2;
    if(a == lft) {
        s = tp[p].num[b];
        ss = 0;
        sss=tp[p].sum[b];
    } else {
        s = tp[p].num[b] - tp[p].num[a-1];
        ss = tp[p].num[a-1];
        sss=tp[p].sum[b]-tp[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;
        ANS+=sss;
        return query(a, b, k-s,p+1, mid+1, rht);
    }
}

void update(int i,int w){
	for(int k=i;k<=n;k+=lowbit(k)){
		arrayTree[k]+=w;
	}
}

LL arraySum(int index){
	if(index==0) return 0;
	LL ret=0;
	for(int i=index;i>=1;i-=lowbit(i))
	ret+=arrayTree[i];
	return ret;
}

LL getsum(int l,int r){
//	cout<<arraySum(r)<<endl;
	return arraySum(r)-arraySum(l-1);
}

int main(){
	int T,Case=0;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		memset(arrayTree,0,sizeof(arrayTree));
		for(int i=1;i<=n;i++){
			scanf("%d",&tp[0].val[i]);
			sorted[i]=tp[0].val[i];
			update(i,sorted[i]);
		}
		ANS=0;
		sort(sorted+1,sorted+1+n);
		build(1,n,0);
		scanf("%d",&m);
		int l,r;
		printf("Case #%d:\n",++Case);
		for(int i=1;i<=m;i++){
			scanf("%d%d",&l,&r);
			l++,r++;
			LL spre=getsum(l,r);
			ANS=0;
			if((r-l+1)%2==0){
				int mid=query(l,r,(r-l+1)/2+1,0,1,n);
				printf("%I64d\n",spre-ANS-ANS);
			}
			else{
				int mid=query(l,r,(r-l+1)/2+1,0,1,n);
				printf("%I64d\n",spre-ANS-ANS-mid);
			}
		}
		puts("");
	}
	return 0;
}

  

时间: 2024-10-12 03:32:20

HDU 3473的相关文章

hdu 3473 Minimum Sum(划分树-sum操作)

划分树.只是考虑求当前区间大于第k值的值得和,和小于第k值的和.显然可以在查询的时候直接搞出来.sum[d][i]表示第d层子区间l,r种l-i的和.写错了一个下标,检查了半辈子... #include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<cmath> #include<queue&g

HDU 3473 Minimum Sum 划分树,数据结构 难度:1

http://acm.hdu.edu.cn/showproblem.php?pid=3473 划分树模板题目,需要注意的是划分树的k是由1开始的 划分树: 参考:http://blog.csdn.net/shiqi_614/article/details/8041390 划分树的定义 划分树定义为,它的每一个节点保存区间[lft,rht]所有元素,元素顺序与原数组(输入)相同,但是,两个子树的元素为该节点所有元素排序后(rht-lft+1)/2个进入左子树,其余的到右子树,同时维护一个num域,

hdu 3473 Minimum Sum 划分树的应用

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3473 Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3427    Accepted Submission(s): 787 Problem Description You are given N positive i

HDU 3473 Minimum Sum 划分树

题目大意:给定一个序列,每次询问给出一个区间,我们需要选择一个数,这个数到区间内所有数的距离之和最小,求最小和 由绝对值不等式可得 当我们选择的这个数是中位数的时候距离和最小 于是这题就转换成了区间第k小 但是这题求的是最小和 于是我们做一个处理 我们多维护一个sum域 sum[i]表示[l,i]区间内划分到左子树中元素的总和 然后我们每次查询第k小时 如果我们进入的是右子树 就把划分到左子树中的元素和累加到left_sum上 然后用前缀和计算出区间的和 计算出right_sum 最后的结果就是

hdu 3473 划分树 ***

题目大意:有一个数列 x1..xn,要求一个数x使得 sigma(abs(xi-x))值最小,很明显,对数列进行排序后最中间的那个数就是x,可用划分树求得,那么如何求和呢,经过计算可知,既然 x 是最中间的那个数,那么最后的和 即为 x左边 xmid-x1+xmid-x2.. +  x(mid+1) - xmid + x(mid+2)-xmid..  整理得 xmid*(lefnum-rignum)+rigsum-lefsum lefnum为划分过程进入左子树的个数,lefsum为进入左子树的数

HDU 3473 Minimum Sum

Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2667    Accepted Submission(s): 609 Problem Description You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you

hdu 3473 Minimum Sum 再来一波划分树,对划分树累觉不爱。

Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3084    Accepted Submission(s): 710 Problem Description You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you

hdu 3473 (划分树)2

Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4611    Accepted Submission(s): 1046 Problem Description You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;