hdu 3473 Minimum Sum(划分树)

Minimum Sum

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4775    Accepted Submission(s): 1083


 

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

 

Author

standy

 

Source

2010 ACM-ICPC Multi-University Training Contest(4)——Host by UESTC

 

Recommend

zhengfeng   |   We have carefully selected several similar problems for you:  3474 1828 1698 1540 1394 

解题思路: 区间内各个数与中位数的绝对值之和最小。

如果区间长度为偶数,则任取一个,如果为奇数则取中间的那个数作为中位数

由此得到一个公式就是区间比中位数小的数的个数lsum*中位数-区间中位数小的数的和+比中位数大的数的和-区间比中位数大

的个数*中位数

化简就是 rsum-lsum+mid*(lnum-rnum);

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define N 100005
int t[20][N],tl[20][N];
LL suml[20][N];
int sor[N];
LL sum[N];

LL lsum,lnum;

void build(int l,int r,int dep)
{
    if(l==r)return ;
    int m = (l+r)>>1;
    int same = m-l+1;
    for(int i=l;i<=r;i++)if(t[dep][i]<sor[m])same--;
    //cout<<l<<" "<<r<<" "<<same<<endl;
    int ln=l;
    int rn=m+1;
    for(int i=l;i<=r;i++)
    {
        if(t[dep][i]<sor[m]||(t[dep][i]==sor[m]&&same>0))
        {
            t[dep+1][ln++]=t[dep][i];
            if(t[dep][i]==sor[m])same--;
            tl[dep][i]=tl[dep][l-1]+ln-l;
            suml[dep][i]=suml[dep][i-1]+t[dep][i];
        }
        else
        {
            t[dep+1][rn++]=t[dep][i];
            tl[dep][i]=tl[dep][i-1];
            suml[dep][i]=suml[dep][i-1];
        }
    }
    build(l,m,dep+1);
    build(m+1,r,dep+1);
}

int query(int l,int r,int ql,int qr,int k,int dep)
{
    if(l==r)return t[dep][l];
    int m=(l+r)>>1;
    int cnt=tl[dep][qr]-tl[dep][ql-1];
    if(cnt>=k)
    {
        int newl = l+tl[dep][ql-1]-tl[dep][l-1];
        int newr = newl+cnt-1;
        return query(l,m,newl,newr,k,dep+1);
    }
    else
    {
        int newr = qr+tl[dep][r]-tl[dep][qr];
        int newl = newr-(qr-ql-cnt);
        //cout<<ql<<" "<<qr<<endl;
        lnum += cnt;
        lsum += suml[dep][qr]-suml[dep][ql-1];
        return query(m+1,r,newl,newr,k-cnt,dep+1);
    }
}

int main()
{
    int tt;
    cin>>tt;
    for(int cas=1;cas<=tt;cas++)
    {
        int n;
        scanf("%d",&n);
        sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&t[0][i]);
            sum[i]=t[0][i]+sum[i-1];
            sor[i]=t[0][i];
        }
        sort(sor+1,sor+1+n);
        build(1,n,0);
        int m;
        scanf("%d",&m);
        printf("Case #%d:\n",cas);
        while(m--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            l++,r++;
            lsum=0,lnum=0;
            int mid=query(1,n,l,r,(r-l)/2+1,0);
            LL rsum = sum[r]-sum[l-1]-lsum-mid;
            LL rnum = r-l-lnum;
            LL ans = rsum - lsum+mid*1LL*(lnum-rnum);
            //printf("mid=%d lnum=%lld rnum=%lld \n",mid,lnum,rnum);
            printf("%lld\n",ans);
        }
        printf("\n");
    }
}

参考博客:https://www.cnblogs.com/oneshot/p/4127018.html

猜你喜欢

转载自blog.csdn.net/weixin_40894017/article/details/81738254
今日推荐