luogu P1471 方差
题目大意
要求我们找一个能够维护区间平均数,区间方差,区间加的数据结构
解法
很容易想到线段树
由于我们需要维护方差,所以我们要推式子
具体的:
\(S^2=\frac{1}{n}[(x_1-\overline{x})^2+(x_2-\overline{x})^2+(x_3-\overline{x})^2+...+(x_n-\overline{x})^2]\)
\(S^2=\frac{1}{n}[x_1^2+x_2^2+x_3^2+...+x_n^2-2(x_1\overline{x}+x_2\overline{x}+x_3\overline{x}+...+x_n\overline{x})+n\overline{x}^2]\)
因为\(n\overline{x}=x_1+x_2+x_3+...+x_n\) ,所以:
\(S^2=\frac{1}{n}[x_1^2+...+x_n^2-n\overline{x}^2]\)
\(S^2=\frac{x_1^2+...+x_n^2}{n}-\overline{x}^2\)
这就是我们的最终形式,其中若区间为\([l,r]\) ,区间平均值为\(\frac{\sum_{i=l}^{r}a_i}{r-l+1}\)
只需要用线段树额外维护区间和就可以了
那么区间加操作对区间平方和的影响呢?
令原来的 \(x_1^2+...+x_n^2=sum\) ,则
\((x_1+k)^2+(x_2+k)^2+...+(x_n+k)^2=sum+2k(x_1+...+x_n)+nk^2\)
就很容易维护了
代码
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long double LD;
struct Node {
int l , r;
LD tag;
LD sum1 , sum2;
};
const int N = 1e5+10;
int n , m;
LD g[N];
Node tr[N*4];
void pushup(int x) {
tr[x].sum1 = tr[x<<1].sum1 + tr[x<<1|1].sum1;
tr[x].sum2 = tr[x<<1].sum2 + tr[x<<1|1].sum2;
}
void pushdown(int x) {
if(tr[x].tag != 0) {
tr[x<<1].sum2 += 2*tr[x].tag*tr[x<<1].sum1+tr[x].tag*tr[x].tag*(tr[x<<1].r-tr[x<<1].l+1);
tr[x<<1].sum1 += tr[x].tag*(tr[x<<1].r-tr[x<<1].l+1);
tr[x<<1|1].sum2 += 2*tr[x].tag*tr[x<<1|1].sum1+tr[x].tag*tr[x].tag*(tr[x<<1|1].r-tr[x<<1|1].l+1);
tr[x<<1|1].sum1 += tr[x].tag*(tr[x<<1|1].r-tr[x<<1|1].l+1);
tr[x<<1].tag += tr[x].tag;
tr[x<<1|1].tag += tr[x].tag;
tr[x].tag = 0;
}
return;
}
void build(int x , int l , int r) {
tr[x].l = l; tr[x].r = r;
if(l == r) {
tr[x].sum1 = g[l];
tr[x].sum2 = g[l]*g[l];
return;
}
int mid = (l+r)>>1;
build(x<<1 , l , mid);
build(x<<1|1 , mid+1 , r);
pushup(x);
return;
}
void modify(int x , int l , int r , LD k) {
if(l <= tr[x].l && tr[x].r <= r) {
tr[x].sum2 += tr[x].sum1*k*2+k*k*(tr[x].r-tr[x].l+1);
tr[x].sum1 += k*(tr[x].r-tr[x].l+1);
tr[x].tag += k;
return;
}
pushdown(x);
int mid = (tr[x].l+tr[x].r)>>1;
if(l <= mid) modify(x<<1 , l , r , k);
if(mid < r) modify(x<<1|1 , l , r , k);
pushup(x);
return;
}
LD query1(int x , int l , int r) {
if(l <= tr[x].l && tr[x].r <= r) return tr[x].sum1;
pushdown(x);
int mid = (tr[x].l+tr[x].r)>>1;
LD res = 0;
if(l <= mid) res += query1(x<<1 , l , r);
if(mid < r) res += query1(x<<1|1 , l , r);
return res;
}
LD query2(int x , int l , int r) {
if(l <= tr[x].l && tr[x].r <= r) return tr[x].sum2;
pushdown(x);
int mid = (tr[x].l+tr[x].r)>>1;
LD res = 0;
if(l <= mid) res += query2(x<<1 , l , r);
if(mid < r) res += query2(x<<1|1 , l , r);
return res;
}
int main() {
scanf("%d%d" , &n , &m);
for(int i = 1 ; i <= n ; i ++)
scanf("%Lf" , &g[i]);
build(1 , 1 , n);
while(m --) {
int opt , x , y;
scanf("%d%d%d" , &opt , &x , &y);
if(opt == 1) {
LD k; scanf("%Lf" , &k);
modify(1 , x , y , k);
}
if(opt == 2) {
LD t = query1(1 , x , y) / (1.0+y-x);
printf("%.4Lf\n" , t);
}
if(opt == 3) {
LD t = query2(1 , x , y) / (1.0+y-x);
LD s = query1(1 , x , y) / (1.0+y-x);
printf("%.4Lf\n" , t-s*s);
}
}
return 0;
}

浙公网安备 33010602011771号