Minimum Sum (划分树)

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;
}

猜你喜欢

转载自blog.csdn.net/M_Y_Y_/article/details/81532308
今日推荐