zoukankan      html  css  js  c++  java
  • HDU 3473 Minimum Sum 划分树

    题意:

    给出一个长度为(n(1 leq n leq 10^5))的序列(a)
    有若干次查询l r:找到一个(x)使得(sum limits_{l leq i leq r} left | x-a_i ight |)的值最小。

    分析:

    有这样一个结论:(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:
    ", 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
    ", ans);
    		}
    		printf("
    ");
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    675 对象的引用-浅拷贝-深拷贝
    674 vue3侦听器watch
    673 vue计算属性:缓存,setter和getter
    明明有了promise,为啥还需要async await?
    Js常用数组方法汇总
    一些非常有用的Js单行代码
    Js获取验证码倒计时
    前端截取字符串:JS截取字符串之substring、substr和slice详解
    javascript全局变量与局部变量
    JS实现快速排序算法
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/5346676.html
Copyright © 2011-2022 走看看