HDU 3473 Minimum Sum 划分树
2016-04-01 23:37
465 查看
题意:
给出一个长度为\(n(1 \leq n \leq 10^5)\)的序列\(a\)有若干次查询
l r:找到一个\(x\)使得\(\sum \limits_{l \leq i \leq r} \left | x-a_i \right |\)的值最小。
分析:
有这样一个结论:\(x\)为子序列的中位数时差的绝对值之和最小。证明也很简单:
将序列中的每个元素对应到数轴上的点,\(x\)是数轴上一个动点。
设\(x\)左边有\(l\)个点,右边有\(r\)个点。
如果动点向右移动\(\Delta x\)距离(而且保证移动后左右两侧点数不变),那么目标值就会变化\(l \Delta x - r \Delta x\)。
如果\(l<r\),这个值会变小;如果\(l>r\),那么向左移动这个值会变小。
直到左右两侧点数相等。
对于这道题就可以很方便地计算出答案:计算出中位数的大小\(mid\),中位数左右两侧数字的个数\(cnt_l,cnt_r\)以及的对应的和\(sum_l,sum_r\)。
最终答案就是:\((mid \cdot cnt_l - sum_l) + (sum_r - mid \cdot cnt_r)\)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 100000 + 10; const int maxd = 20; int n; int sorted[maxn]; int T[maxd][maxn], cnt[maxd][maxn]; LL sum[maxd][maxn], pre[maxn]; void build(int d, int L, int R) { int M = (L + R) / 2; int lsame = M - L + 1; for(int i = L; i <= R; i++) if(T[d][i] < sorted[M]) lsame--; int lpos = L, rpos = M + 1; for(int i = L; i <= R; i++) { if(i == L) { sum[d][i] = 0; cnt[d][i] = 0; } else { sum[d][i] = sum[d][i-1]; cnt[d][i] = cnt[d][i-1]; } if(T[d][i] < sorted[M] || (T[d][i] == sorted[M] && lsame)) { cnt[d][i]++; sum[d][i] += T[d][i]; T[d+1][lpos++] = T[d][i]; if(T[d][i] == sorted[M]) lsame--; } else T[d+1][rpos++] = T[d][i]; } if(L < M) build(d + 1, L, M); if(M + 1 < R) build(d + 1, M + 1, R); } LL q_kth, q_sum; void query(int d, int L, int R, int qL, int qR, int k) { if(L == R) { q_kth = T[d][L]; q_sum += T[d][L]; return; } int M = (L + R) / 2; int numl; if(qL == L) numl = 0; else numl = cnt[d][qL - 1]; int numr = cnt[d][qR]; int num = numr - numl; if(num >= k) { query(d + 1, L, M, L + numl, L + numr - 1, k); } else { LL suml; if(qL == L) suml = 0; else suml = sum[d][qL - 1]; q_sum += sum[d][qR] - suml; numl = qL - L - numl; numr = qR - L + 1 - numr; query(d + 1, M+1, R, M+1+numl, M+numr, k - num); } } int main() { int _; scanf("%d", &_); for(int kase = 1; kase <= _; kase++) { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", sorted + i); pre[i] = pre[i - 1] + sorted[i]; T[0][i] = sorted[i]; } sort(sorted + 1, sorted + 1 + n); build(0, 1, n); printf("Case #%d:\n", kase); int q; scanf("%d", &q); while(q--) { int l, r; scanf("%d%d", &l, &r); l++; r++; int k = (r - l) / 2 + 1; q_sum = 0; query(0, 1, n, l, r, k); LL ans = q_kth * k - q_sum; ans += (pre[r] - pre[l-1] - q_sum) - q_kth * (r - l + 1 - k); printf("%lld\n", ans); } printf("\n"); } return 0; }
相关文章推荐
- This version of the rendering library is more recent than your version of ADT plug-in
- window系统bat方式启动tomcat出现java.lang.OutOfmemoryError:PermGen Space 错误
- 【Redis基本数据结构】动态字符串
- java17天
- 第九道ACM程序题
- 【Redis基本数据结构】链表
- bzoj2440 完全平方数
- C实现strstr函数
- 中介者模式-吵架和好得找宿舍老大
- Markdown语法帮助
- C++作业2
- IO流(二)_File类
- css position
- java单例-积木系列
- 分布式配置 tachyon 并运行Hadoop例子 MapReduce
- linux下socket通信,server和client简单例子
- thinkphp
- bzoj3992【SDOI2015】序列统计
- 洛谷 1855 榨取kkksc03
- 关于Java中形参与实参的理解