HDU 3473 Minimum Sum 划分树

来源:互联网 发布:智慧猫儿童编程 编辑:程序博客网 时间:2024/05/14 02:25
有n个数,每次给出一段区间l,r,选出一个数X使得|X-Xi|(l<=i<=r)尽量小,X显然是中位数。此外还要得到区间和,这个可以在划分树递归的时候累加,当递归左子树的时候,可以加上所有大于中位数的数,递归右子树的时候可以减去所有小于中位数的数。
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef __int64 LL;const int maxn = 100010;int tree[20][maxn], toleft[20][maxn], a[maxn];LL sum[20][maxn];void build(int l, int r, int dep){    if(l == r)    {        sum[dep][l] = tree[dep][l];        return;    }    int m = (l+r) >> 1;    int tol = m-l+1;    for(int i = l; i <= r; i++)    {        if(tree[dep][i] < a[m])            tol--;        sum[dep][i] = tree[dep][i];        if(i > l)            sum[dep][i] += sum[dep][i-1];    }    int L = l, R = m+1;    for(int i = l; i <= r; i++)    {        if(tree[dep][i] < a[m])            tree[dep+1][L++] = tree[dep][i];        else if(tree[dep][i] == a[m] && tol > 0)        {            tree[dep+1][L++] = tree[dep][i];            tol--;        }        else            tree[dep+1][R++] = tree[dep][i];        toleft[dep][i] = toleft[dep][l-1] + L-l;    }    build(l, m, dep+1);    build(m+1, r, dep+1);}LL ans;int query(int L, int R, int l, int r, int dep, int k){    if(l == r)        return tree[dep][l];    int m = (L+R) >> 1;    int cnt = toleft[dep][r]-toleft[dep][l-1];    int ltol = toleft[dep][l-1]-toleft[dep][L-1];    int ltor = l-L-ltol;    int mtol = cnt;    int mtor = r-l+1-cnt;    if(cnt >= k)    {        if(mtor > 0)        {            if(ltor > 0)                ans += sum[dep+1][mtor+ltor+m]-sum[dep+1][ltor+m];            else                ans += sum[dep+1][mtor+m];        }        int nextl = L + toleft[dep][l-1]-toleft[dep][L-1];        int nextr = nextl + cnt - 1;        return query(L, m, nextl, nextr, dep+1, k);    }    else    {        if(mtol > 0)        {            if(ltol > 0)                ans -= sum[dep+1][mtol+ltol+L-1]-sum[dep+1][ltol+L-1];            else                ans -= sum[dep+1][mtol+L-1];        }        int nextr = r + toleft[dep][R]-toleft[dep][r];        int nextl = nextr-(r-l-cnt);        return query(m+1, R, nextl, nextr, dep+1, k-cnt);    }}int main(){    int T, cas = 1;    scanf("%d", &T);while(T--)    {        int n;        scanf("%d", &n);        for(int i = 1; i <= n; i++)        {            scanf("%d", &tree[0][i]);            a[i] = tree[0][i];        }        sort(a+1, a+n+1);        int q;        scanf("%d", &q);        build(1, n, 0);        printf("Case #%d:\n", cas++);        while(q--)        {            int l, r;            scanf("%d %d", &l, &r);            l++, r++;            ans = 0;            int m = (r-l)/2+1;            int tmp = query(1, n, l, r, 0, m);            if((r-l+1)%2 == 0)                ans -= tmp;            printf("%I64d\n", ans);        }        puts("");    }return 0;}
0 0