[BZOJ4821][SDOI2017]相关分析

bzoj
luogu

题意

你需要维护两个数组\(\{x_i\},\{y_i\}\),资瓷一下三种操作。
1、给出\(l,r\),设\(\overline x,\overline y\)分别表示区间\([l,r]\)\(x_i,y_i\)的平均数,求:

\[\frac{\sum_{i=l}^r(x_i-\overline x)(y_i-\overline y)}{\sum_{i=l}^r(x_i-\overline x)^2} \]

2、给出\(l,r,S,T\),令区间\([l,r]\)内每个\(x_i+=S,y_i+=T\)
3、给出\(l,r,S,T\),令区间\([l,r]\)内每个\(x_i=S+i,y_i=i+T\)

sol

把询问式的括号拆了,利用\(\overline x*(r-l+1)=\sum_{i=l}^rx_i\)化简一下式子:

\[\frac{\sum x_iy_i+\frac 1{r-l+1}\sum x_i*\sum y_i}{\sum x_i^2+\frac 1{r-l+1}\sum x_i*\sum x_i} \]

所以只要维护区间的\(\sum x,\sum y,\sum xy,\sum x^2\)就行了。
操作2是一个区间加,有:
\(\sum(x+\Delta x)(y+\Delta y)=\sum xy+\sum x*\Delta y+\sum y*\Delta x+(r-l+1)*\Delta x*\Delta y\)
操作3可以看作是先把区间变成\(x_i=y_i=i\)再做一次2操作。
区间覆盖的时候要把操作2的\(lazy\)清空。
\(\sum_{i=1}^{n}i=\frac 12n*(n+1)\)
\(\sum_{i=1}^{n}i^2=\frac 16n*(n+1)*(2n+1)\)

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5+5;
int n,m,tag_c[N<<2];double X[N],Y[N],tag_x[N<<2],tag_y[N<<2];
struct data{double x,y,xy,xx;}t[N<<2];
data operator + (data a,data b){
	return (data){a.x+b.x,a.y+b.y,a.xy+b.xy,a.xx+b.xx};
}
void build(int x,int l,int r){
	if (l==r){
		t[x].x=X[l];t[x].y=Y[l];
		t[x].xy=t[x].x*t[x].y;t[x].xx=t[x].x*t[x].x;
		return;
	}
	int mid=l+r>>1;
	build(x<<1,l,mid);build(x<<1|1,mid+1,r);
	t[x]=t[x<<1]+t[x<<1|1];
}
void cover1(int x,int l,int r,double S,double T){
	double len=r-l+1;
	t[x].xy+=t[x].x*T+t[x].y*S+S*T*len;
	t[x].xx+=2*t[x].x*S+S*S*len;
	t[x].x+=S*len;t[x].y+=T*len;
	tag_x[x]+=S;tag_y[x]+=T;
}
double cal1(int x){return (double)x*(x+1)/2;}
double cal2(int x){return (double)x*(x+1)*(2*x+1)/6;}
void cover2(int x,int l,int r){
	t[x].x=t[x].y=cal1(r)-cal1(l-1);
	t[x].xy=t[x].xx=cal2(r)-cal2(l-1);
	tag_c[x]=1;tag_x[x]=tag_y[x]=0;
}
void pushdown(int x,int l,int r){
	int mid=l+r>>1;
	if (tag_c[x]){
		cover2(x<<1,l,mid);cover2(x<<1|1,mid+1,r);
		tag_c[x]=0;
	}
	if (tag_x[x]||tag_y[x]){
		cover1(x<<1,l,mid,tag_x[x],tag_y[x]);
		cover1(x<<1|1,mid+1,r,tag_x[x],tag_y[x]);
		tag_x[x]=tag_y[x]=0;
	}
}
void modify1(int x,int l,int r,int ql,int qr,double S,double T){
	if (l>=ql&&r<=qr) {cover1(x,l,r,S,T);return;}
	pushdown(x,l,r);int mid=l+r>>1;
	if (ql<=mid) modify1(x<<1,l,mid,ql,qr,S,T);
	if (qr>mid) modify1(x<<1|1,mid+1,r,ql,qr,S,T);
	t[x]=t[x<<1]+t[x<<1|1];
}
void modify2(int x,int l,int r,int ql,int qr){
	if (l>=ql&&r<=qr) {cover2(x,l,r);return;}
	pushdown(x,l,r);int mid=l+r>>1;
	if (ql<=mid) modify2(x<<1,l,mid,ql,qr);
	if (qr>mid) modify2(x<<1|1,mid+1,r,ql,qr);
	t[x]=t[x<<1]+t[x<<1|1];
}
data query(int x,int l,int r,int ql,int qr){
	if (l>=ql&&r<=qr) return t[x];
	pushdown(x,l,r);int mid=l+r>>1;
	if (qr<=mid) return query(x<<1,l,mid,ql,qr);
	if (ql>mid) return query(x<<1|1,mid+1,r,ql,qr);
	return query(x<<1,l,mid,ql,qr)+query(x<<1|1,mid+1,r,ql,qr);
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i) scanf("%lf",&X[i]);
	for (int i=1;i<=n;++i) scanf("%lf",&Y[i]);
	build(1,1,n);while (m--){
		int opt,l,r;scanf("%d%d%d",&opt,&l,&r);
		if (opt==1){
			data ans=query(1,1,n,l,r);
			double p=ans.xy-ans.x*ans.y/(r-l+1);
			double q=ans.xx-ans.x*ans.x/(r-l+1);
			printf("%.10lf\n",p/q);
		}else{
			double S,T;scanf("%lf%lf",&S,&T);
			if (opt==3) modify2(1,1,n,l,r);
			modify1(1,1,n,l,r,S,T);
		}
	}
	return 0;
}
posted @ 2018-05-26 12:25  租酥雨  阅读(345)  评论(0编辑  收藏  举报