# 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 some intervals [l, r]. For each interval, you need to find a number x to make as small as possible!

Input
The first line is an integer T (T <= 10), indicating the number of test cases. For each test case, an integer N (1 <= N <= 100,000) comes first. Then comes N positive integers x (1 <= x <= 1,000, 000,000) in the next line. Finally, comes an integer Q (1 <= Q <= 100,000), indicting there are Q queries. Each query consists of two integers l, r (0 <= l <= r < N), meaning the interval you should deal with.

Output
For the k-th test case, first output “Case #k:” in a separate line. Then output Q lines, each line is the minimum value of . Output a blank line after every test case.

Sample Input
2 5 3 6 2 2 4 2 1 4 0 2 2 7 7 2 0 1 1 1

Sample Output
Case #1: 6 4 Case #2: 0 0

x 是最中间的那个数，那么最后的和 即为 x左边 xmid-x1+xmid-x2.. +  x(mid+1) - xmid + x(mid+2)-xmid..  整理得 xmid*(lefnum-rignum)+rigsum-lefsum

lefnum为划分过程进入左子树的个数，lefsum为进入左子树的数之和

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX 100100

using namespace std ;

long long sum[25][MAX];
int sorted[MAX] , tree[25][MAX] ,toLeft[25][MAX] ;
void creat(int L , int R , int deep)
{
if(L == R)
{
sum[deep][L]=tree[deep][L] ;
return ;
}
int mid = (L+R)>>1 , same = mid-L+1;

for(int i = L ; i <= R ; ++i)
{
if(tree[deep][i]<sorted[mid])
--same ;
sum[deep][i] = tree[deep][i] ;
if(i>L)	sum[deep][i] += sum[deep][i-1] ;
}
int ls = L ,rs = mid+1;
for(int i = L ; i <= R ; ++i)
{
int flag = 0 ;
long long num = 0;
if(tree[deep][i]<sorted[mid] || (tree[deep][i]==sorted[mid] && same))
{
tree[deep+1][ls++]=tree[deep][i] ;
if(tree[deep][i] == sorted[mid])
--same ;
flag = 1 ;
}
else
{
tree[deep+1][rs++] = tree[deep][i] ;
}
toLeft[deep][i] = toLeft[deep][i-1]+flag ;
}
creat(L,mid,deep+1) ;
creat(mid+1,R,deep+1) ;
}
long long ans = 0;
int query(int L , int R , int x , int y , int k , int deep)
{
if(x == y)
{
return tree[deep][x] ;
}
int  mid = (L+R)>>1;
int lxl = toLeft[deep][x-1] - toLeft[deep][L-1] ;
int lyl = toLeft[deep][y] - toLeft[deep][L-1] ;
int xyl = toLeft[deep][y] - toLeft[deep][x-1] ;
int lxr = x-L-lxl ;
int lyr = y-L+1-(toLeft[deep][y]-toLeft[deep][L-1]) ;

if(k<=xyl)
{
if(lyr>0)
{
if(lxr>0)
{
ans += sum[deep+1][mid+lyr]-sum[deep+1][mid+lxr];
}
else
{
ans += sum[deep+1][mid+lyr] ;
}
}
return query(L,mid,L+lxl,L+lyl-1,k,deep+1);
}
else
{
if(lyl>0)
{
if(lxl>0)	ans-=sum[deep+1][L+lyl-1]-sum[deep+1][L+lxl-1];
else	ans -= sum[deep+1][L+lyl-1] ;
}
return query(mid+1,R,mid+lxr+1,mid+lyr,k-xyl,deep+1);
}

}

int main()
{
int t ;
scanf("%d",&t);
for(int i = 1 ; i <= t ; ++i)
{
int n ;
scanf("%d",&n);
memset(toLeft,0,sizeof(toLeft)) ;
for(int j = 1 ; j <= n ; ++j)
{
scanf("%d",&sorted[j]) ;
tree[0][j] = sorted[j] ;
}
sort(sorted+1 , sorted+n+1) ;
creat(1,n,0) ;
int r ;
printf("Case #%d:\n",i) ;
scanf("%d",&r) ;
for(int j = 0 ; j < r ; ++j)
{
int l,ri;
scanf("%d%d",&l,&ri) ;
++l,++ri;
int k = (ri-l)/2+1;
ans = 0 ;
int d = query(1,n,l,ri,k,0);
if((ri-l+1)%2 == 0)
{
ans -= d ;
}
printf("%I64d\n",ans);
}
printf("\n") ;
}
return 0 ;
}


#### 划分树and主席树

2012-08-29 13:17:04

#### hdu3473Minimum Sum【划分树sum维护】

2016-01-29 21:36:35

#### 划分树模板+模板题--hdu4251

2015-08-07 13:21:18

#### hdu 3473 Minimum Sum（划分树）

2015-11-12 17:53:08

#### HDU 3473 Minimum Sum 划分树

2014-09-24 15:12:39

#### HDU 3473 Minimum Sum 划分树

2016-05-17 23:19:44

#### Minimum Sum - HDU 3473 划分树

2015-07-11 15:11:00

#### HDU 3473 Minimum Sum （划分树）

2013-09-06 15:30:06

#### hdu 3473 Minimum Sum 划分树

2012-04-11 09:09:22

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

2014-05-14 13:11:06