线段树维护区间方差
方差
区间方差
还教室
- 解题思路:
利用线段树维护 \(a_i\) 与 \(a_i^2\) \(( 1\leq i \leq n)\) 两个数列 ,然后使用一个 \(lazytag\) 来记录是否进行了区间加,最后输出方差的时候使用 $$ s^2 =\sum\limits_{i=1}^n (a_i-\overline a )^2 =(\sum \limits_{i=1}na_i2+n\times\overline a^2-2 n\overline a$$ 就可以计算出区间方差
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 9;
#define int long long
int n, m;
class seg
{
public:
#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)
struct node
{
int l, r;
double tag;
double sum, fsum; // 算术和与平方和
};
node t[maxn<<2];
double a[maxn];
void build(int p, int l, int r)
{
t[p].l = l, t[p].r = r;
if (l == r)
{
t[p].sum = a[l];
t[p].fsum = t[p].sum * t[p].sum;
return;
}
int mid = l + r >> 1;
build(ls(p), l, mid);
build(rs(p), mid + 1, r);
t[p].sum = t[ls(p)].sum + t[rs(p)].sum;
t[p].fsum = t[ls(p)].fsum + t[rs(p)].fsum;
}
void pushdown(int p)
{
if (t[p].tag)
{
if(t[p].l!=t[p].r)
{
t[ls(p)].fsum+=(t[ls(p)].r-t[ls(p)].l+1)*t[p].tag*t[p].tag+2*t[p].tag*t[ls(p)].sum;
t[rs(p)].fsum+=(t[rs(p)].r-t[rs(p)].l+1)*t[p].tag*t[p].tag+2*t[p].tag*t[rs(p)].sum;
t[ls(p)].tag+=t[p].tag;
t[rs(p)].tag+=t[p].tag;
t[rs(p)].sum += (t[rs(p)].r - t[rs(p)].l + 1) * t[p].tag;
t[ls(p)].sum += (t[ls(p)].r - t[ls(p)].l + 1) * t[p].tag;
t[p].tag=0;
}
else
{
t[p].tag=0;
}
}
}
void change(int p, int l, int r,double x)
{
if(l<=t[p].l&&t[p].r<=r)
{
t[p].fsum+=(t[p].r-t[p].l+1)*x*x+2*x*t[p].sum;
t[p].sum+=x*(t[p].r-t[p].l+1);
t[p].tag+=x;
return ;
}
if(t[p].r<l||t[p].l>r)return ;
pushdown(p);
int mid=t[p].l+t[p].r>>1;
if(mid>=l)change(ls(p),l,r,x);
if(mid<r) change(rs(p),l,r,x);
t[p].sum = t[ls(p)].sum + t[rs(p)].sum;
t[p].fsum = t[ls(p)].fsum + t[rs(p)].fsum;
}
double asksum(int p,int l,int r)
{
if(l<=t[p].l&&t[p].r<=r)
{
return t[p].sum;
}
if(t[p].r<l||t[p].l>r)return 0;
double ans=0;
pushdown(p);
int mid=t[p].l+t[p].r>>1;
if(mid>=l)ans+=asksum(ls(p),l,r);
if(mid<r) ans+=asksum(rs(p),l,r);
return ans;
}
double askfsum(int p,int l,int r)
{
if(l<=t[p].l&&t[p].r<=r)
{
return t[p].fsum;
}
if(t[p].r<l||t[p].l>r)return 0;
double ans=0;
pushdown(p);
int mid=t[p].l+t[p].r>>1;
if(mid>=l)ans+=askfsum(ls(p),l,r);
if(mid<r) ans+=askfsum(rs(p),l,r);
return ans;
}
};
seg T;
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> T.a[i];
}
T.build(1,1,n);
int t,x,y;
double k;
for(int i=1;i<=m;i++)
{
std::cin>>t;
if(t==1)
{
cin>>x>>y;cin>>k;T.change(1,x,y,k);
}
else if(t==2)
{
std::cin>>x>>y;
printf("%.4f\n",(double)T.asksum(1,x,y)*1.0/(1.0*(y-x+1)));
}
else
{
cin>>x>>y;
double t1=(double)T.asksum(1,x,y)/(y-x+1);
double t2=(double)T.askfsum(1,x,y);
printf("%.4f\n",(double)(t2-t1*t1*(y-x+1))/(y-x+1));
}
}
return 0;
}
标签:方差,int,double,线段,rs,tag,ls,区间,sum
From: https://www.cnblogs.com/cxjy0322/p/18351443