洛谷 P1471 方差
Posted Last_order
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1471 方差相关的知识,希望对你有一定的参考价值。
题目链接
区间加,区间查询,显然的线段树 & 分块
说实话第一眼看到这个题的时候我是很懵的:
线段树每个区间要维护什么呢?
我们定义 \\(Sum = \\sum\\limits_{i=1}^n A_i = A_1 + A_2 + \\ldots + A_n\\)
\\(\\qquad \\ \\ \\; \\; \\; Pow = \\sum\\limits_{i=1}^n A_i^2 = A_1^2 + A_2^2 + \\ldots + A_n^2\\)
还要知道平均数的公式 \\(\\overline{A} = \\cfrac{Sum}{n}\\)
先把方差的计算公式展开一下:
而上面的式子可以由 \\(Sum\\) 和 \\(Pow\\) 求得(\\(n\\) 为区间长度),所以我们只要维护每个区间的区间和以及平方和即可。(●\'◡\'●)
然后我们再来求一下区间修改的式子。
若是给 \\(A_1\\) 到 \\(A_n\\) 这段区间加上有个数 \\(k\\),区间和比较简单就不列式子了,区间平方和就为:
然后我们就得到了这道题所要用的所有公式,只需将 \\(1 \\sim n\\) 这个区间推广到题目给的区间 \\(l \\sim r\\) 即可。
于是我们的pushdown
(下传懒标记)和add
(区间加)函数就很好写了:
inline void add(int l, int r, double k, int node){
if(l <= t[node].l && t[node].r <= r){
t[node].lazy += k;
t[node].pow += (k * t[node].sum * 2) + k * k * (t[node].r - t[node].l + 1); //乘 2 不能用位运算代替,因为是浮点型的;
t[node].sum += (t[node].r - t[node].l + 1) * k;
return;
}
if(t[node].lazy) pushdown(node);
int mid = t[node].l + t[node].r >> 1;
if(l <= mid) add(l, r, k, node << 1);
if(mid < r) add(l, r, k, node << 1 | 1);
update(node);
}
inline void pushdown(int node){ //看似很长,其实就是按照上面的公式来的;
t[node << 1].lazy += t[node].lazy;
t[node << 1 | 1].lazy += t[node].lazy;
t[node << 1].pow += (t[node << 1].sum * t[node].lazy * 2) + (t[node << 1].r - t[node << 1].l + 1) * t[node].lazy * t[node].lazy;
t[node << 1].sum += (t[node << 1].r - t[node << 1].l + 1) * t[node].lazy;
t[node << 1 | 1].pow += (t[node << 1 | 1].sum * t[node].lazy * 2) + (t[node << 1 | 1].r - t[node << 1 | 1].l + 1) * t[node].lazy * t[node].lazy;
t[node << 1 | 1].sum += (t[node << 1 | 1].r - t[node << 1 | 1].l + 1) * t[node].lazy;
t[node].lazy = 0;
}
其中每个节点维护的sum
和pow
与上文中意义一致。
for(int i = 1; i <= m; i++){
scanf("%d %d %d", &check, &x, &y);
if(check == 1){
scanf("%lf", &k);
add(x, y, k, 1);
}
double Average = ask_sum(x, y, 1) / (y - x + 1); //这里的 Average 表示区间的平均值,用变量记录一下减少重复运算;
if(check == 2){
printf("%.4lf\\n", Average);
}
if(check == 3){
double Pow = ask_pow(x, y, 1);
printf("%.4lf\\n", Pow / (y - x + 1) - (Average * Average));
}
}
由于比较长就在这不放全部代码了,剩下的部分都是线段树的基本操作。
还有唯一一点要注意的就是题目中给的数列为实数,不一定是整数,存数列的数组一定要开double
啊!!!
至于文章开头提到的分块,太麻烦不想写了。
以上是关于洛谷 P1471 方差的主要内容,如果未能解决你的问题,请参考以下文章