HDU 3473 Minimum Sum (划分树)

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!
 
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
【分析】先贪心,要想结果最小,则必须取中位数,这就是划分树做的事了,直接模板。
 
#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;
}
原文地址:https://www.cnblogs.com/jianrenfang/p/6368946.html