HDU 3473 Minimum Sum
2012-03-14 22:02
267 查看
HDU_3437
比较容易证明,x应该取区间的中位数,于是问题就转化成了求[l,r]区间内大小排第(l+r)/2+1的数,然后将和计算出来即可。
求区间的中位数可以用划分树来实现,但是和却不可以在求得中位数后再利用原序列直接计算,因为原区间的元素是无序的,我们没办法进行作差求和。联想作差求和的条件,即要明确哪些数是比中位数大,哪些数比中位数小,而划分树恰好左子树的元素总是比右子树小,于是如果中位数在左子树中,我们自然可以将右子树中[l,r]区间内的数与中位数的差先求出来,如果中位数在右子树中,我们就可以先将左子树中[l,r]区间内的数与中位数的差先求出来,求和的过程可以在求得中位数的具体值后回溯的时候实现。为了实现快速求和,我们在建划分树时可以额外建一个数组A[d][i],表示在第d层的某节点上第i个元素及之前的元素之和。
比较容易证明,x应该取区间的中位数,于是问题就转化成了求[l,r]区间内大小排第(l+r)/2+1的数,然后将和计算出来即可。
求区间的中位数可以用划分树来实现,但是和却不可以在求得中位数后再利用原序列直接计算,因为原区间的元素是无序的,我们没办法进行作差求和。联想作差求和的条件,即要明确哪些数是比中位数大,哪些数比中位数小,而划分树恰好左子树的元素总是比右子树小,于是如果中位数在左子树中,我们自然可以将右子树中[l,r]区间内的数与中位数的差先求出来,如果中位数在右子树中,我们就可以先将左子树中[l,r]区间内的数与中位数的差先求出来,求和的过程可以在求得中位数的具体值后回溯的时候实现。为了实现快速求和,我们在建划分树时可以额外建一个数组A[d][i],表示在第d层的某节点上第i个元素及之前的元素之和。
#include<stdio.h> #include<string.h> #include<stdlib.h> #define MAXK 20 #define MAXD 100010 int N, M, sa[MAXD], a[MAXD], rank[MAXK][MAXD], h[MAXK][MAXD]; long long int A[MAXK][MAXD], ans; int cmp(const void *_p, const void *_q) { int *p = (int *)_p, *q = (int *)_q; if(a[*p] == a[*q]) return *p - *q; return a[*p] - a[*q]; } void init() { int i, j, k; scanf("%d", &N); for(i = 1; i <= N; i ++) { scanf("%d", &a[i]); sa[i] = i; } } void build(int lx, int rx, int d) { if(lx == rx) { A[d][lx] = a[sa[rank[d][lx]]]; return ; } int i, j, k, p = 0, mid = (lx + rx) / 2; for(i = lx; i <= rx; i ++) { if(rank[d][i] <= mid) rank[d + 1][lx + p ++] = rank[d][i]; else rank[d + 1][mid + i - lx + 1 - p] = rank[d][i]; h[d][i] = p; A[d][i] = a[sa[rank[d][i]]] + (i == lx ? 0 : A[d][i - 1]); } build(lx, mid, d + 1); build(mid + 1, rx, d + 1); } int search(int lx, int rx, int x, int y, int k, int d) { if(lx == rx) return sa[rank[d][lx]]; int j, n, m, mid = (lx + rx) / 2, tx, ty; n = h[d][y], m = x == lx ? 0 : h[d][x - 1]; if(n - m >= k) { j = search(lx, mid, lx + m, lx + n - 1, k, d + 1); tx = mid + 1 + x - lx - m, ty = mid + 1 + y - lx - n; if(tx <= ty) ans += A[d + 1][ty] - (tx == mid + 1 ? 0 : A[d + 1][tx - 1]) - (long long int)(ty - tx + 1) * a[j]; } else { j = search(mid + 1, rx, mid + 1 + x - lx - m, mid + 1 + y - lx - n, k - n + m, d + 1); tx = lx + m, ty = lx + n - 1; if(tx <= ty) ans += (long long int)(ty - tx + 1) * a[j] - A[d + 1][ty] + (tx == lx ? 0 : A[d + 1][tx - 1]); } return j; } void solve() { int i, j, k, x, y; qsort(sa + 1, N, sizeof(sa[0]), cmp); for(i = 1; i <= N; i ++) rank[0][sa[i]] = i; build(1, N, 0); scanf("%d", &M); for(i = 0; i < M; i ++) { scanf("%d%d", &x, &y); ++ x, ++ y; k = (y - x) / 2 + 1; ans = 0; search(1, N, x, y, k, 0); printf("%I64d\n", ans); } } int main() { int t, tt; scanf("%d", &t); for(tt = 0; tt < t; tt ++) { init(); printf("Case #%d:\n", tt + 1); solve(); printf("\n"); } return 0; }
相关文章推荐
- HDU 3473 Minimum Sum 划分树
- hdu 3473 Minimum Sum
- HDU 3473-Minimum Sum(划分树-求区间sigma最小值)
- hdu 3473 Minimum Sum 划分树
- HDU 3473 Minimum Sum 划分树
- HDU 3473 Minimum Sum (划分树)
- hdu 3473 Minimum Sum
- hdu 3473 Minimum Sum
- HDU 3473 Minimum Sum(划分树)
- hdu 3473 Minimum Sum 划分树
- HDU 3473 Minimum Sum 划分树
- HDU 3473 Minimum Sum【划分树】
- HDU 3473 Minimum Sum
- HDU 3473 Minimum Sum (划分树)
- HDU 3473 Minimum Sum
- hdu 3473 Minimum Sum
- HDU 3473 Minimum Sum(划分树)
- HDU 3473 Minimum Sum (划分树)
- hdu 3473 Minimum Sum 划分树
- hdu 3473 Minimum Sum