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

Posted tea-egg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
    


以上是关于hdu3473区间条件极值 - 区间 差的绝对值 之和的最小的主要内容,如果未能解决你的问题,请参考以下文章

hdu5289 Assignment (区间查询最大值最小值,st算法...)

HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)

hdu 6609 区间条件前缀和 + 二分

如何求标准差的置信区间

拉格朗日乘数法

一元三次方程求解