hdu3473区间条件极值 - 区间 差的绝对值 之和的最小

题目传送门//res tp hdu

目的

对长度为n的区间,给定q个子区间,求一x,使得区间内所有元素与x的绝对值之和最小。
多测。
n 1e5
q 1e5
ai [1,1e9] (i∈[1,n]);

数据结构

划分树

tip

该划分树维护的cnt并非元素所在区间内,该元素之前进入左子树的元素个数,而是整个区间内,该元素之前进入左子树的元素个数。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int L = 100000+50;
typedef long long ll;
int n,q;
int tree[18][L];
int cnt[18][L];
ll sum[18][L],ans;
int a[L],sorted[L];

void build(int de,int l,int r){
    if(l == r){
        sum[de][l] = sum[de][l-1] + tree[de][l];return;
    }
    if(de == 0){
        for(int i = 1;i<=r;++i)
            tree[de][i] = a[i];
    }
    int mi=(l+r)>>1;
    int scnt = mi - l + 1;
    ll M = sorted[mi];
    for(int i = l;i<=mi;++i) if(sorted[i] < M)
        scnt--;
    int pl = l,pr = mi + 1;
    for(int i = l;i<=r;++i){
        ll num =tree[de][i];
        if(num == M){
            if(scnt){
                scnt--;
                tree[de+1][pl++] = num;
                cnt[de][i]++;
            }
            else
                tree[de+1][pr++] = num;
        }
        else if(num < M){
            tree[de+1][pl++] = num;
            cnt[de][i]++;
        }
        else
            tree[de+1][pr++] = num;
        sum[de][i] = sum[de][i-1] + tree[de][i];
        cnt[de][i] += cnt[de][i-1];
    }
    build(de+1,l,mi);
    build(de+1,mi+1,r);
}

ll query(int de,int L,int R,int l,int r,int k){
    if(L == R) return tree[de][L];

    int mi = (L + R)>>1;
    int lo1,lo2,hi1,hi2;
    int CNT = cnt[de][r] - cnt[de][l-1];
    lo1 = L + cnt[de][l-1] - cnt[de][L-1];
    hi1 = L + cnt[de][r] - cnt[de][L-1] - 1;
    lo2 = mi + 1 + l - L - cnt[de][l-1] + cnt[de][L-1];
    hi2 = mi + 1 + r - L - cnt[de][r] + cnt[de][L-1];
    if(k <= CNT){
        if(hi2 >= lo2)
            ans += sum[de+1][hi2] - sum[de+1][lo2-1];
        return query(de+1,L,mi,lo1,hi1,k);
    }
    else{
        if(hi1>=lo1)
        ans -= sum[de+1][hi1] - sum[de+1][lo1-1];
        return query(de+1,mi+1,R,lo2,hi2, k - CNT);
    }
}




int main(){
    int T,l,r;
    int icase = 1;
    scanf(" %d",&T);
    while(T--){
        scanf(" %d",&n);
        memset(sum,0,sizeof(sum));
        memset(cnt,0,sizeof(cnt));
        for(int i = 1;i<=n;++i){
            scanf(" %d",a + i);
            sorted[i] = a[i];
        }
        sort(sorted+1,sorted+1+n);
        build(0,1,n);
        scanf(" %d",&q);
        printf("Case #%d:\n",icase++);
        while(q--){
            ans = 0;
            scanf(" %d %d",&l,&r);
            l++;r++;
            ll t = query(0,1,n,l,r,(r - l)/2 + 1);
            if((r-l)%2 == 1)
                ans -= t;
            printf("%lld\n", ans);
        }
        cout<<endl;
    }
}

上一篇:算法竞赛进阶指南 图论 最短路


下一篇:机器学习评价指标大汇总