zoukankan      html  css  js  c++  java
  • 【洛谷】【线段树】P1471 方差

    【题目背景:】

    滚粗了的HansBug在收拾旧数学书,然而他发现了什么奇妙的东西。

    【题目描述:】

    蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数。他想算算这个数列的平均数和方差。

    【输入格式:】

    第一行包含两个正整数N、M,分别表示数列中实数的个数和操作的个数。

    第二行包含N个实数,其中第i个实数表示数列的第i项。

    接下来M行,每行为一条操作,格式为以下两种之一:

    操作1:1 x y k ,表示将第x到第y项每项加上k,k为一实数。

    操作2:2 x y ,表示求出第x到第y项这一子数列的平均数。

    操作3:3 x y ,表示求出第x到第y项这一子数列的方差。

    【输出格式:】

    输出包含若干行,每行为一个实数,即依次为每一次操作2或操作3所得的结果(所有结果四舍五入保留4位小数)。

    输入样例#15 5
    1 5 4 2 3
    2 1 4
    3 1 5
    1 1 1 1
    1 2 2 -1
    3 1 5
    输出样例#13.0000
    2.0000
    0.8000
    输入输出样例

    【算法分析:】

    支持区间修改,区间询问,常规做法线段树

    关于平均值;

      维护一个区间和,区间平均值就是区间和/区间长度

    关于方差:

      设ave为序列a的平均值

      s2 = [(a1 - ave)2 + (a2 - ave)2 + ... + (an - ave)2] / n

      展开可得:s2 = a12 + a22 + ... + an - 2 * ave(a1 + a2 + ... + an) + n * ave2

    可以发现,只需要多维护一个区间平方和,就可以求出方差。

    但如果要修改某一区间内元素的值呢?

      (a1 + v)2 + (a2 + v)2 + ... + (an + v)2

    = a12 + a22 + ... + an2 + 2v(a1 + a2 + .. + an) + n * v2

    维护区间平方和时,标记下传和修改被包含区间值的操作是一样的,答案就很显然了.

    注意坑点:读入的序列是实型,方差平均值和要修改的值也是实型,修改时传参的修改值也要是实型.

    【代码:】

     1 //P1471 方差
     2 #include<iostream>
     3 #include<cstdio>
     4 using namespace std;
     5 
     6 const int MAXN = 1e5 + 1;
     7 
     8 int n, m;
     9 double a[MAXN];
    10 struct Segment {
    11     double sum, squ, lazy;
    12 }t[MAXN << 2];
    13 
    14 void Build(int o, int l, int r) {
    15     if(l == r) {
    16         t[o].sum = a[l];
    17         t[o].squ = a[l] * a[l];
    18     }
    19     else {
    20         int mid = (l + r) >> 1;
    21         Build(o << 1, l, mid);
    22         Build(o << 1|1, mid + 1, r);
    23         t[o].sum = t[o << 1].sum + t[o << 1|1].sum;
    24         t[o].squ = t[o << 1].squ + t[o << 1|1].squ;
    25     }
    26 }
    27 inline void down(int o, int len) {
    28     if(!t[o].lazy) return;
    29     t[o << 1].squ += 2 * t[o].lazy * t[o << 1].sum 
    30                         + t[o].lazy * t[o].lazy * (len - (len >> 1));
    31     t[o << 1|1].squ += 2 * t[o].lazy * t[o << 1|1].sum 
    32                          + t[o].lazy * t[o].lazy * (len >> 1);
    33     t[o << 1].sum += t[o].lazy * (len - (len >> 1));
    34     t[o << 1|1].sum += t[o].lazy * (len >> 1);
    35     t[o << 1].lazy += t[o].lazy;
    36     t[o << 1|1].lazy += t[o].lazy;
    37     t[o].lazy = 0;
    38 }
    39 void Update(int o, int l, int r, int ul, int ur, double v) {
    40     if(ul <= l && r <= ur) {
    41         t[o].squ += 2 * v * t[o].sum + v * v * (r - l + 1);
    42         t[o].sum += v * (r - l + 1);
    43         t[o].lazy += v;
    44     }
    45     else {
    46         down(o, r - l + 1);
    47         int mid = (l + r) >> 1;
    48         if(ul <= mid) Update(o << 1, l, mid, ul, ur, v);
    49         if(ur > mid) Update(o << 1|1, mid + 1, r, ul, ur, v);
    50         t[o].sum = t[o << 1].sum + t[o << 1|1].sum;
    51         t[o].squ = t[o << 1].squ + t[o << 1|1].squ;
    52     }
    53 }
    54 
    55 double ssum, ssqu; 
    56 void Query(int o, int l, int r, int ql, int qr) {
    57     if(ql <= l && r <= qr) {
    58         ssum += t[o].sum;
    59         ssqu += t[o].squ;
    60     }
    61     else {
    62         down(o, r - l + 1);
    63         int mid = (l + r) >> 1;
    64         if(ql <= mid) Query(o << 1, l, mid, ql, qr);
    65         if(qr > mid) Query(o << 1|1, mid + 1, r, ql, qr);
    66     }
    67 }
    68 
    69 inline double Average(int l, int r) {
    70     ssum  = ssqu = 0;
    71     Query(1, 1, n, l, r);
    72     return ssum * 1.0 / (r - l + 1);
    73 }
    74 inline double S2(int l, int r) {
    75     ssum = ssqu = 0;
    76     int num = r - l + 1;
    77     Query(1, 1, n, l, r);
    78     double ave = ssum * 1.0 / num;
    79     double ret = ssqu - 2 * ave * ssum + num * ave * ave;
    80     return ret / num;
    81 }
    82 
    83 int main() {
    84     scanf("%d%d", &n, &m);
    85     for(int i = 1; i <= n; ++i)
    86         scanf("%lf", &a[i]);
    87     Build(1, 1, n);
    88     while(m--) {
    89         int fl, x, y;
    90         scanf("%d%d%d", &fl, &x, &y);
    91         if(fl == 2) printf("%.4lf
    ", Average(x, y));
    92         else if(fl == 3) printf("%.4lf
    ", S2(x, y));
    93         else {
    94             double k;
    95             scanf("%lf", &k);
    96             Update(1, 1, n, x, y, k);
    97         }
    98     }
    99 }                                    
  • 相关阅读:
    快速排序(详解)
    14.linux-platform机制实现驱动层分离(详解)
    13.Linux键盘按键驱动 (详解)
    Linux-hexdump命令调试event驱动—详解(13)
    Android开发final的用法
    Android控件RecyclerView的基本用法
    搜索关键词分析——以个人博客网站为例
    java.net.SocketException: Software caused connection abort: socket write error
    Android layout属性大全
    java中 label 配合 break continue 使用方法
  • 原文地址:https://www.cnblogs.com/devilk-sjj/p/9048399.html
Copyright © 2011-2022 走看看