HDU3473 Minimum Sum
原题传送:http://acm.hdu.edu.cn/showproblem.php?pid=3473
做出这题感觉又帅了。
划分树。
一看题目很容易想到每次查询求的x就是该区间排序后的中位数,再看看规模,不难想出得用划分树nlog(n)。
尽管题目给了8s的时限,然而,如果每次只是求出中位数在循环一遍区间去求答案,也会TLE,所以,另开数组lsum[],在建树的时候记录放到左子树的元素的和,则可在每次询问的时候,如果在树的某一层要进入右子树,那么,该区间进入左子树的所有元素的和都是小于中位数的。
另外,如果这题写丑了会卡掉内存的,当时我写的时候是开两个数组lsum[]和rsum[],结果爆了。这道题目也是让自己各种错误都尝了一遍。
View Code
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 typedef __int64 LL; 5 const int maxn = 100000+2; 6 7 struct node 8 { 9 int num[maxn]; 10 int val[maxn]; 11 LL lsum[maxn]; 12 }tree[20]; 13 int a[maxn]; 14 LL sum[maxn]; 15 16 void build(int l, int r, int d) 17 { 18 if(l == r) 19 return ; 20 21 int mid = (l + r) >> 1, save = mid - l + 1, saved = 0; 22 int lp = l, rp = mid + 1; 23 for(int i = l; i <= r; i ++) 24 if(tree[d].val[i] < a[mid]) --save; 25 for(int i = l; i <= r; i ++) 26 { 27 if(i == l) 28 tree[d].num[i] = 0; 29 else 30 tree[d].num[i] = tree[d].num[i - 1]; 31 32 if(tree[d].val[i] < a[mid] || (saved < save && tree[d].val[i] == a[mid])) 33 { 34 tree[d + 1].val[lp] = tree[d].val[i]; 35 ++tree[d].num[i]; 36 tree[d].lsum[i] = tree[d].lsum[i - 1] + tree[d].val[i]; 37 lp++; 38 if(tree[d].val[i] == a[mid]) ++saved; 39 } 40 else 41 { 42 tree[d + 1].val[rp] = tree[d].val[i]; 43 tree[d].lsum[i] = tree[d].lsum[i - 1]; 44 rp++; 45 } 46 } 47 build(l, mid, d + 1); 48 build(mid + 1, r, d + 1); 49 } 50 51 void query(int s, int t, int k, int l, int r, int d, LL &x, LL &lsum) 52 { 53 if(s == t) 54 { 55 x = tree[d].val[s]; 56 return ; 57 } 58 int mid = (l + r) >> 1; 59 int s1 = tree[d].num[s - 1]; 60 int s2 = tree[d].num[t]; 61 if(s - 1 < l) s1 = 0; 62 if(s2 - s1 >= k) 63 { 64 query(l + s1, l + s2 - 1, k, l, mid, d + 1, x, lsum); 65 } 66 else 67 { 68 int k1 = (s == 1 ? 0 : s - l - s1); 69 int k2 = (t - s + 1) - (s2 - s1); 70 lsum += tree[d].lsum[t] - tree[d].lsum[s - 1]; 71 query(mid + 1 + k1, mid + k1 + k2, k - (s2 - s1), mid + 1, r, d + 1, x, lsum); 72 } 73 } 74 75 int main() 76 { 77 int n, m, T, u, v; 78 scanf("%d", &T); 79 for(int cas = 1; cas <= T; cas++) 80 { 81 scanf("%d", &n); 82 sum[0] = 0; 83 for(int i = 1; i <= n; i ++) 84 { 85 scanf("%d", &a[i]); 86 tree[0].lsum[i] = tree[0].val[i] = a[i]; 87 sum[i] = sum[i - 1] + a[i]; 88 } 89 std::sort(a + 1, a + 1 + n); 90 build(1, n, 0); 91 scanf("%d", &m); 92 printf("Case #%d:\n", cas); 93 while(m --) 94 { 95 scanf("%d%d", &u, &v); 96 u++, v++; 97 LL x, lsum = 0; 98 query(u, v, (v - u) / 2 + 1, 1, n, 0, x, lsum); 99 LL ans = ((sum[v] - sum[u - 1] - lsum - x) - lsum - x * ((v - u) % 2)); 100 printf("%I64d\n", ans); 101 } 102 putchar('\n'); 103 } 104 return 0; 105 }