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便是区间内的中位数(排好序之后位置最中间的数)。
这里题目说区间里数的个数一定为奇数,所以不用考虑中位数不止一个的情况。
不知道划分树的可以戳这里
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <string>
#include <cmath>
#include <stack>
#include <queue>
#include <map>
#define MAX 0x3f3f3f3f
using namespace std;
const int MAXN=1e5+100;
typedef long long LL;
int n;
int tree[20][MAXN];
int num[20][MAXN];
int sorted[MAXN];
int x[MAXN];
void Build(int l,int r,int level)
{
if(l==r)
return ;
int mid=(l+r)/2,isame=mid-l+1;
for(int i=l; i<=r; i++)
{
if(tree[level][i]<sorted[mid])
isame--;
}
int sl=l,sr=mid+1;
for(int i=l; i<=r; i++)
{
if(l==i)
num[level][i]=0;
else
num[level][i]=num[level][i-1];
if(tree[level][i]<sorted[mid]||tree[level][i]==sorted[mid]&&isame>0)
{
num[level][i]++;
tree[level+1][sl++]=tree[level][i];
if(tree[level][i]==sorted[mid])
isame--;
}
else
{
tree[level+1][sr++]=tree[level][i];
}
}
Build(l,mid,level+1);
Build(mid+1,r,level+1);
}
int query(int l,int r,int left,int right,int k,int level)
{
if(left==right)
return tree[level][left];
int preleft;
int laleft;
if(l==left)
{
preleft=0;
laleft=num[level][right];
}
else
{
preleft=num[level][left-1];
laleft=num[level][right]-preleft;
}
int mid=(l+r)/2;
if(laleft>=k)
{
int newl=preleft+l;
int newr=newl+laleft-1;
query(l,mid,newl,newr,k,level+1);
}
else
{
int newl=mid+1+(left-l-preleft);
int newr=newl+(right-left+1-laleft)-1;
query(mid+1,r,newl,newr,k-laleft,level+1);
}
}
int main()
{
int t;
cin>>t;
for(int j=1; j<=t; j++)
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&tree[0][i]);
sorted[i]=tree[0][i];
}
sort(sorted+1,sorted+1+n);
Build(1,n,0);
int m;
scanf("%d",&m);
printf("Case #%d:\n",j);
for(int i=1; i<=m; i++)
{
int a,b;
scanf("%d%d",&a,&b);
a++,b++;
int k=(b-a+1)/2+1; //中位数的位置,x也就是第k大的数
LL ans=0,m;
m=query(1,n,a,b,k,0);
for(int p=a;p<=b;p++)
ans+=abs(tree[0][p]-m);
printf("%lld\n",ans);
}
cout <<endl;
}
return 0;
}