MinimumSum
描述
已知含有N个正整数的数列 x0, x1 ... xN-1。对于每个询问的区间[l, r](包含左右端点),在区间内找出一个数x使得尽量小。
输入
每组数据中:
第一行是数列长度N(1 <= N <= 100,000)
第二行给出数列中的N个数xi (1 <= x <=1,000, 000,000)
第三行为询问数Q(1 <= Q <= 100,000),每个询问给出区间的左右端点l, r(0 <= l <= r < N)
输出
输出Q行,每一行是询问区间[l,r]的.最小值
输入样例1:
5
3 6 2 2 4
2
1 4
0 2
输出样例1:
6
4
输入样例2:
2
7 7
2
0 1
1 1
输出样例2:
0
0
数据规模
30%的数据,N<=1000,Q<=1000。
所有数据,N<=100000,Q<=100000, 1<= xi <= 1,000, 000,000, 0 <= l<= r < N
解析:
一道划分树,只需要在原来的基础上再多维护小于中位数的个数和他们的的和。。。
在划分树中,即每次查询时累加分到左子树的个数和他们的和。。。
还有,要注意一些细节部分,因为我又手残了,写程序半小时,Debug三小时。。。悲剧啊!!!
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
#define N 100005
int n,m;
int lnum;
long long lsum;
long long val[22][N],sum[22][N],num[22][N];
long long order[N];
long long he[N];
void build(int h,int l,int r)
{
if(l==r)return ;
int mid=(l+r)>>1;
int same=mid-l+1;
for(int i=l;i<=r;i++)
if(val[h][i]<order[mid])same--;
int cl=l,cr=mid+1;
for(int i=l;i<=r;i++)
{
int flag=0;
if(val[h][i]<order[mid] || (val[h][i]==order[mid]&&same))
{
flag=1;
val[h+1][cl++]=val[h][i];
sum[h][i]=sum[h][i-1]+val[h][i];
if(val[h][i]==order[mid])same--;
}
else
{
sum[h][i]=sum[h][i-1];
val[h+1][cr++]=val[h][i];
}
num[h][i]=num[h][i-1]+flag;
}
build(h+1,l,mid);
build(h+1,mid+1,r);
}
long long query(int h,int ll,int rr,int l,int r,int k)
{
//cout<<ll<<' '<<rr<<endl;
if(ll==rr)return val[h][ll];
int mid=(ll+rr)>>1;
int lx=num[h][l-1]-num[h][ll-1];
int ly=num[h][r]-num[h][l-1];
int rx=l-1-ll+1-lx;
int ry=r-l+1-ly;
if(k<=ly)return query(h+1,ll,mid,ll+lx,ll+lx+ly-1,k);
else
{
lnum+=ly;
lsum+=sum[h][r]-sum[h][l-1];
return query(h+1,mid+1,rr,mid+1+rx,mid+1+rx+ry-1,k-ly);
}
}
void read()
{
freopen("MinimumSum.in","r",stdin);
freopen("MinimumSum.out","w",stdout);
}
void work()
{
int T;
scanf("%d",&T);
for(int z=1;z<=T;z++)
{
scanf("%d",&n);
for(int i=1;i<=20;i++)
sum[i][0]=0;
memset(he,0,sizeof(he));
for(int i=1;i<=n;i++)
{
scanf("%d",&val[0][i]);
order[i]=val[0][i];
he[i]=he[i-1]+order[i];
}
sort(order+1,order+n+1);
build(0,1,n);
printf("Case #%d:\n",z);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int l,r; lnum=0;lsum=0;
scanf("%d%d",&l,&r);
l++;r++;
int len=r-l+1;
int le=len/2;
if(len%2!=0)le++;
//cout<<le<<endl;
long long ans1=query(0,1,n,l,r,le);
//cout<<ans1<<endl;
long long ss=he[r]-he[l-1];
long long s1=lnum*ans1-lsum;
long long s2=(ss-lsum)-ans1*(len-lnum);
cout<<s1+s2<<endl;
}
}
}
int main()
{
read();
work();
return 0;
}