• 洛谷 P1471 方差


    Description

    洛谷传送门

    Solution

    一道非常经典的线段树问题,下面我们来分析一下。

    题目要求我们支持区间加,求区间平均值,求区间方差。

    区间加和区间平均值都很简单,唯独这个区间方差要如何维护呢?

    我们先来看一下方差的式子:

    [len = r - l + 1 ]

    [S^2 = frac{1}{len}sumlimits_{i=l}^r{(a_i - overline a)^2} ]

    把平方拆开:

    [S^2 = frac{1}{len}sumlimits_{i=l}^r{(a_i^2 - 2a_ioverline a + overline a^2)} ]

    (sum) 拆开:

    [S^2 = frac{1}{len}(sumlimits_{i=l}^r{a_i^2} - 2overline asumlimits_{i=l}^r{a_i} + sumlimits_{i=l}^r{overline a^2}) ]

    然后我们发现 (overline a) 就是我们询问平均值时计算出来的数,所以我们只需要再维护一个区间平方和就可以 (O(logn)) 内计算出答案。

    那么如何维护区间平方和呢?

    再来看下面的式子:

    [(a + b) ^ 2 = a ^ 2 + 2ab + b ^ 2 ]

    这是个人都知道。

    当操作范围变成一个区间时……

    [s_2\,^2 = sumlimits_{i = l}^r{(a_i + b)^2} ]

    同样把括号拆开:

    [s_2\,^2 = sumlimits_{i = l}^r{(a_i^2 + 2a_ib + b^2)} ]

    然后拆 (sum)

    [s_2\,^2 = sumlimits_{i = l}^ra_i^2 + 2bsumlimits_{i = l}^ra_i + sumlimits_{i = l}^rb^2 ]

    再来看这时我们已知什么:

    [sum = sumlimits_{i = l}^ra_i ]

    [s_1\,^2 = sumlimits_{i = l}^r{a_i^2} ]

    于是 (s_2\,^2) 就变成了:

    [s_2\,^2 = s_1\,^2 + 2 * b * sum + b^2 * len ]

    这样区间平方和就可以维护了。

    最后计算方差的式子我就不多写了。自己稍微推一下吧(其实也没什么了)。

    实在不会的话看代码应该也可以理解。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define ls rt << 1
    #define rs rt << 1 | 1
    
    using namespace std;
    
    const int N = 1e5 + 10;
    int n, m;
    double a[N], sum[N << 2], sum2[N << 2];
    double lazy[N << 2]; 
    
    inline void pushup(int rt){
    	sum[rt] = sum[ls] + sum[rs];
    	sum2[rt] = sum2[ls] + sum2[rs];
    }
    
    inline void pushdown(int l, int r, int rt){
    	if(lazy[rt]){
    		int mid = (l + r) >> 1;
    		sum2[ls] += lazy[rt] * lazy[rt] * (mid - l + 1) + 2 * sum[ls] * lazy[rt];
    		sum2[rs] += lazy[rt] * lazy[rt] * (r - mid) + 2 * sum[rs] * lazy[rt];
    		sum[ls] += lazy[rt] * (mid - l + 1);
    		sum[rs] += lazy[rt] * (r - mid);
    		lazy[ls] += lazy[rt];
    		lazy[rs] += lazy[rt];
    		lazy[rt] = 0;
    	}
    }
    
    inline void build(int l, int r, int rt){
    	if(l == r){
    		sum[rt] = a[l];
    		sum2[rt] = a[l] * a[l];
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(l, mid, ls);
    	build(mid + 1, r, rs);
    	pushup(rt);
    }
    
    inline void update(int L, int R, double k, int l, int r, int rt){
    	if(L <= l && r <= R){
    		sum2[rt] += k * k * (r - l + 1) + 2 * sum[rt] * k;
    		sum[rt] += k * (r - l + 1);
    		lazy[rt] += k;
    		return;
    	}
    	pushdown(l, r, rt);
    	int mid = (l + r) >> 1;
    	if(L <= mid) update(L, R, k, l, mid, ls);
    	if(R > mid) update(L, R, k, mid + 1, r, rs);
    	pushup(rt);
    }
    
    inline double query_1(int L, int R, int l, int r, int rt){//查询一次和
    	if(L <= l && r <= R)
    		return sum[rt];
    	pushdown(l, r, rt);
    	int mid = (l + r) >> 1;
    	double res = 0;
    	if(L <= mid) res += query_1(L, R, l, mid, ls);
    	if(R > mid) res += query_1(L, R, mid + 1, r, rs);
    	return res;
    }
    
    inline double query_2(int L, int R, int l, int r, int rt){//查询二次(平方)和
    	if(L <= l && r <= R)
    		return sum2[rt];
    	pushdown(l, r, rt);
    	int mid = (l + r) >> 1;
    	double res = 0;
    	if(L <= mid) res += query_2(L, R, l, mid, ls);
    	if(R > mid) res += query_2(L, R, mid + 1, r, rs);
    	return res;
    }
    
    signed main(){
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= n; i++)
    		scanf("%lf", &a[i]);
    	build(1, n, 1);
    	for(int i = 1; i <= m; i++){
    		int op, l, r;
    		double k;
    		scanf("%d%d%d", &op, &l, &r);
    		if(op == 1){
    			scanf("%lf", &k);
    			update(l, r, k, 1, n, 1);
    		}else if(op == 2) printf("%.4lf
    ", query_1(l, r, 1, n, 1) / (r - l + 1));
    		else{
    			double sum = query_1(l, r, 1, n, 1);//一次和
    			double avg = sum / (r - l + 1);//平均数
    			double res = query_2(l, r, 1, n, 1);//二次(平方)和
    			printf("%.4lf
    ", (res - 2 * sum * avg + avg * avg * (r - l + 1)) / (r - l + 1));
    		}
    	}
    	return 0;
    }
    

    End

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15412887.html

  • 相关阅读:
    js的基本数据类型有哪些?
    页面优化的方式有哪些?
    为什么要用rem
    sass开发过程中遇到的几个坑
    js事件监听
    js数组去重的方法
    什么是怪异盒模型
    Cookie SameSite属性介绍及其在ASP.NET项目中的应用
    HttpServlet在第一个Servlet程序中的知识点
    Myeclipse 2017 创建第一个servlet步骤
  • 原文地址:https://www.cnblogs.com/xixike/p/15412887.html
Copyright © 2020-2023  润新知