Minimum Sum
Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4156 Accepted Submission(s): 941
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!
![](http://acm.hdu.edu.cn/data/images/C284-1005-1.jpg)
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.
![](http://acm.hdu.edu.cn/data/images/C284-1005-1.jpg)
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
【分析】先贪心,要想结果最小,则必须取中位数,这就是划分树做的事了,直接模板。
#include <iostream> #include <cstring> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <time.h> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #define met(a,b) memset(a,b,sizeof a) #define pb push_back #define lson(x) ((x<<1)) #define rson(x) ((x<<1)+1) using namespace std; typedef long long ll; const int N=1e5+50; const int M=N*N+10; long long ans; struct P_Tree { int n; int tree[20][N]; int sorted[N]; int toleft[20][N]; ll sum[N]; ll lsum[20][N]; void init(int len) { n=len; sum[0]=0; for(int i=0; i<20; i++)tree[i][0]=toleft[i][0]=lsum[i][0]=0; for(int i=1; i<=n; i++) { scanf("%d",&sorted[i]); tree[0][i]=sorted[i]; sum[i]=sum[i-1]+sorted[i]; } sort(sorted+1,sorted+n+1); build(1,n,0); } void build(int l,int r,int dep) { if(l==r)return; int mid=(l+r)>>1; int same=mid-l+1; for(int i=l; i<=r; i++) { if(tree[dep][i]<sorted[mid]) same--; } int lpos = l; int rpos = mid+1; for(int i = l; i <= r; i++) { if(tree[dep][i] < sorted[mid]) { tree[dep+1][lpos++] = tree[dep][i]; lsum[dep][i] = lsum[dep][i-1] + tree[dep][i]; } else if(tree[dep][i] == sorted[mid] && same > 0) { tree[dep+1][lpos++] = tree[dep][i]; lsum[dep][i] = lsum[dep][i-1] + tree[dep][i]; same --; } else { tree[dep+1][rpos++] = tree[dep][i]; lsum[dep][i] = lsum[dep][i-1]; } toleft[dep][i] = toleft[dep][l-1] + lpos -l; } build(l,mid,dep+1);//递归建树 build(mid+1,r,dep+1); } int query(int L,int R,int l,int r,int dep,int k) { if(l==r)return tree[dep][l]; int mid=(L+R)>>1; int cnt=toleft[dep][r]-toleft[dep][l-1]; int s=toleft[dep][l-1]-toleft[dep][L-1]; if(cnt>=k) { int newl=L+toleft[dep][l-1]-toleft[dep][L-1]; int newr=newl+cnt-1; return query(L,mid,newl,newr,dep+1,k);//注意 } else { ans+=(ll)(lsum[dep][r]-lsum[dep][l-1]); //printf("l: %d r: %d ans: %lld %lld %lld ",l,r,ans,lsum[dep][r],lsum[dep][l-1]); int newr=r+toleft[dep][R]-toleft[dep][r]; int newl=newr-(r-l-cnt); return query(mid+1,R,newl,newr,dep+1,k-cnt);//注意 } } } tre; int main() { int iCase=0; int n,m,T; int l,r; scanf("%d ",&T); while(T--) { scanf("%d",&n); tre.init(n); scanf("%d",&m); printf("Case #%d: ",++iCase); while(m--) { ans=0; scanf("%d%d",&l,&r); l++; r++; int k=(r-l)/2+1; ll aver=tre.query(1,n,l,r,0,k); ll res=0; res=tre.sum[r]-tre.sum[l-1]-aver*(r-l+1-k)-ans-aver; res+=(k-1)*aver-ans; printf("%I64d ",res); } puts(""); } return 0; }