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

      

  • 相关阅读:
    洛谷 P1508 Likecloud-吃、吃、吃
    Codevs 1158 尼克的任务
    2017.10.6 国庆清北 D6T2 同余方程组
    2017.10.6 国庆清北 D6T1 排序
    2017.10.3 国庆清北 D3T3 解迷游戏
    2017.10.3 国庆清北 D3T2 公交车
    2017.10.3 国庆清北 D3T1 括号序列
    2017.10.4 国庆清北 D4T1 财富
    2017.10.7 国庆清北 D7T2 第k大区间
    2017.10.7 国庆清北 D7T1 计数
  • 原文地址:https://www.cnblogs.com/tobec/p/3237747.html
Copyright © 2011-2022 走看看