线段树方差 RE 求调
  • 板块题目总版
  • 楼主SilverLi
  • 当前回复0
  • 已保存回复0
  • 发布时间2023/5/29 20:19
  • 上次更新2023/10/23 14:21:29
查看原帖
线段树方差 RE 求调
688783
SilverLi楼主2023/5/29 20:19

P1471 方差

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=4e5+5;
double t[N],add[N];
double f[N];
int n,m,a[N];
inline void ad(int p,int len) {
	if(add[p]) {
		f[p<<1]+=2*add[p]*t[p<<1]+(len-(len>>1))*add[p]*add[p];
        f[p<<1|1]+=2*add[p]*t[p<<1|1]+(len>>1)*add[p]*add[p];
        t[p<<1]+=(len-(len>>1))*add[p];
        t[p<<1|1]+=(len>>1)*add[p];
		add[p<<1]+=add[p];
		add[p<<1|1]+=add[p];
		add[p]=0;
	}
}
void build(int l,int r,int p) {
	if(l==r) {	t[p]=a[l],f[p]=a[l]*a[l];return;}
	int m=(l+r)/2;
	build(l,m,p<<1);build(m+1,r,p<<1|1);
	t[p]=t[p<<1]+t[p<<1|1];
	f[p]=f[p<<1]+f[p<<1|1];
}
#define len (r-l+1)
void upd(int l,int r,int s,int T,int p,double w) {
	if(l>=s&&r<=T) {
		f[p]=2*w*t[p]+w*w*len,
		t[p]+=w*len,add[p]+=w;
		return;
	}
	int m=(l+r)/2;
	ad(p,r-l+1);
	if(s<=m)	upd(l,m,s,T,p<<1,w);
	if(T>m)	upd(m+1,r,s,T,p<<1|1,w);
	t[p]=t[p<<1]+t[p<<1|1];
	f[p]=f[p<<1]+f[p<<1|1];
	return;
}
double sum(int l,int r,int s,int T,int p) {
	if(l>=s&&r<=T)	return t[p];
	int m=(l+r)/2;
	double su=0.0;
	ad(p,r-l+1);
	if(s<=m)	su=sum(l,m,s,T,p<<1);
	if(T>m)	su+=sum(m+1,r,s,T,p<<1|1);
	return su;
}
double ax(int l,int r,int s,int T,int p) {
	if(l>=s&&r<=T)	return f[p];
	int m=(l+r)/2;
	double su=0.0;
	ad(p,r-l+1);
	if(s<=m)	su=ax(l,m,s,T,p<<1);
	if(T>m)	su+=ax(m+1,r,s,T,p<<1|1);
	return su;
}
signed main() {
	cin>>n>>m;
	for(int i=1;i<=n;++i)	cin>>a[i];
	build(1,n,1);
	while(m--) {
		int opt,x,y;
		double k;
		cin>>opt>>x>>y;
		if(opt==1) {
			cin>>k;
			upd(1,n,x,y,1,k);
		} else if(opt==2) {
			printf("%.4lf\n",sum(1,n,x,y,1)/(y-x+1));
		} else {
			double tt=sum(1,n,x,y,1)/(y-x+1);
			double tf=ax(1,n,x,y,1)/(y-x+1);
			printf("%.4lf\n",tf-tt*tt);
		}
	}
	return 0;
}
2023/5/29 20:19
加载中...