zoukankan      html  css  js  c++  java
  • hdu 3473 Minimum Sum 划分树

    http://acm.hdu.edu.cn/showproblem.php?pid=3473

    对于xl,xl+1……xr,使得[xi-x]和最小,显然x应当为其中的中位数。中位数可以通过求K大数解决,划分树可搞。

    对于求和,分为两部分,小于x的部分,大于y的部分,在建树的时候也保存下来分到左子树中的数的和。

    最终的和为ave*(lnum-rnum)+rsum-lsum

    ave为中位数,lnum为左子数的数量,也就是小于中位数的数量,rnum为右子数,lsum表示小于中位数部分的和

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define ls (rt<<1)
    #define rs ((rt<<1)|1)
    #define mid ((t[rt].l+t[rt].r)>>1)
    #define ll long long
    const int maxn = 100010;
    struct node {
        int l , r;
    }t[maxn<<2];
    int sa[maxn],num[20][maxn],cnt[20][maxn];
    ll Lsum[20][maxn],sum[maxn];
    int n , q;
    void build(int l,int r,int rt,int deep) {
        t[rt].l = l; t[rt].r = r;
        if(l == r) return;
        int mid_val = sa[mid],lsum=mid-l+1;
        for(int i=l;i<=r;i++)
            if(num[deep][i] < mid_val)
                lsum --;
        int L = l , R = mid + 1;
        for(int i=l;i<=r;i++) {
            if(i == l) cnt[deep][i] = 0;
            else cnt[deep][i] = cnt[deep][i-1];
            Lsum[deep][i]=Lsum[deep][i-1];
            if(num[deep][i]<mid_val || num[deep][i]==mid_val && lsum>0) {
                num[deep+1][L++] = num[deep][i];
                cnt[deep][i] ++;
                Lsum[deep][i]+=(ll)num[deep][i];
                if(num[deep][i] == mid_val)
                    lsum --;
            }
            else num[deep+1][R++] = num[deep][i];
        }
        build(l,mid,ls,deep+1);
        build(mid+1,r,rs,deep+1);
    }
    int lnum;
    ll lsum;
    int query(int l,int r,int rt,int k,int deep) {
        if(l == r) return num[deep][l];
        int s1 , s2;
        if(t[rt].l == l) s1 = 0;
        else s1 = cnt[deep][l-1];
        s2 = cnt[deep][r] - s1;
        if(k <= s2)
            return query(t[rt].l+s1,t[rt].l+s1+s2-1,ls,k,deep+1);
        int b1 = l-1-t[rt].l+1-s1;
        int b2 = r-l+1-s2;
        lnum += s2;
        lsum = (ll)lsum+Lsum[deep][r]-Lsum[deep][l-1];
        return query(mid+1+b1,mid+1+b1+b2-1,rs,k-s2,deep+1);
    }
    int main() {
        int T , cas = 1;
        scanf("%d" , &T);
        while(T--) {
            printf("Case #%d:
    " , cas++);
            scanf("%d" , &n);
            sum[0] = 0;
            for(int i=1;i<=n;i++) {
                scanf("%d",&num[1][i]);
                sa[i] = num[1][i];
                sum[i] = (ll)sum[i-1] + sa[i];
            }
            sort(sa+1,sa+1+n);
            build(1,n,1,1);
            scanf("%d",&q);
            while(q--) {
                int l , r,  k;
                scanf("%d%d",&l,&r);
                l ++; r ++;
                k = (r-l+2)>>1;
                lnum = lsum = 0;
                int ave = query(l,r,1,k,1);
                printf("%I64d
    ",ave*(lnum-(r-l+1-lnum))+sum[r]-sum[l-1]-lsum-lsum);
            }
            puts("");
        }
        return 0;
    }
    

      

  • 相关阅读:
    转:【实用教程】阿里云服务器的配置和使用
    C# 定制错误页面
    C# Session进程外存储
    NOIP200101数的计算
    周末舞会
    queue 队列
    信息学作文
    求三个数的平均数
    Hello world
    Django-Form组件-forms.Form
  • 原文地址:https://www.cnblogs.com/tobec/p/3237747.html
Copyright © 2011-2022 走看看