P3707 [SDOI2017]相关分析

题目链接: P3707 [SDOI2017]相关分析

题目大意: 你有一个数列,你需要维护某一段数的回归方程的系数 a a a a = ∑ L R ( x i − x ˉ ) ( y i − y ˉ ) ∑ L R ( x i − x ˉ ) 2 a=\frac{\sum_{L}^R{(x_i-\bar{x})(y_i-\bar{y})}}{\sum_L^R(x_i-\bar{x})^2} a=LR(xixˉ)2LR(xixˉ)(yiyˉ)有三个操作分别是求区间 [ L , R ] [L,R] [L,R]上的 a a a,将区间 [ L , R ] [L,R] [L,R]上的所有 x + s x+s x+s,所有 y + t y+t y+t,以及将区间 [ L , R ] [L,R] [L,R]上的 x x x值改为 i + s i+s i+s, y y y的值改为 i + t i+t i+t其中 ( L ≤ i ≤ R ) (L\leq{i}\leq{R}) (LiR)

题目分析: 这个题看起来不难,但是一看就麻烦的要死;我们先把 a a a的那个式子拆开,可以写为 a = ∑ L R x i y i − ∑ L R x i y ˉ ∑ L R ( x i 2 − 2 x i x ˉ + x ˉ 2 ) a=\frac{\sum_L^Rx_iy_i-\sum_L^Rx_i\bar{y}}{\sum_L^R(x_i^2-2x_i\bar{x}+\bar{x}^2)} a=LR(xi22xixˉ+xˉ2)LRxiyiLRxiyˉ然后就可以考虑通过线段树维护这个式子了,我们需要维护的量有 ∑ x y , ∑ x 2 , ∑ y , ∑ x \sum xy,\sum x^2,\sum y,\sum x xy,x2,y,x
先看比较简单的操作2,对于 x x x y y y的修改都是简单的区间操作,考虑对于 ∑ L R x y \sum_L^R{xy} LRxy,修改之后变为了 ∑ L R ( x + s ) ( y + t ) \sum_L^R{(x+s)(y+t)} LR(x+s)(y+t),因此我们要在原来的值的基础上加上 t ∑ L R x + s ∑ L R y + ( R − L + 1 ) ∗ s t t\sum_L^R{x}+s\sum_L^R{y}+(R-L+1)*st tLRx+sLRy+(RL+1)st,对于维护 x 2 x^2 x2的操作与之类似。需要注意的一点是2操作与3操作的次序问题,我们假设总是先执行3操作,后执行2操作,因此需要在执行3操作时将之前的2操作清零。
然后我们看一下比较复杂的三操作,对于 ∑ L R x y \sum_L^R xy LRxy 将其修改为 ∑ L R ( i + s ) ( i + t ) \sum_L^R{(i+s)(i+t)} LR(i+s)(i+t)我们只需要求出 ∑ L R ( i 2 + ( s + t ) i + s t ) \sum_L^R{(i^2+(s+t)i+st)} LR(i2+(s+t)i+st),以这个值来替换原来的值,同样 x 2 x^2 x2可以用类似的方法求出来。下面放题目代码

题目代码:

#include<stdio.h>
#include<algorithm>
#include<string.h>
#define mxn 100005
using namespace std;
int n,m;
struct Tree{
	double xsum,ysum,xysum,x2sum;
	double x1lazy,y1lazy,x2lazy,y2lazy;
	int lazy2,lazy1;
}tree[mxn<<2];
double x[mxn],y[mxn];
void pushup(int loc){
	tree[loc].xsum=tree[loc<<1].xsum+tree[loc<<1|1].xsum;
	tree[loc].ysum=tree[loc<<1].ysum+tree[loc<<1|1].ysum;
	tree[loc].x2sum=tree[loc<<1].x2sum+tree[loc<<1|1].x2sum;
	tree[loc].xysum=tree[loc<<1].xysum+tree[loc<<1|1].xysum;
}
void Build(int loc,int L,int R){
	if(L==R){
		tree[loc].xsum=x[L];
		tree[loc].ysum=y[L];
		tree[loc].x2sum=x[L]*x[L];
		tree[loc].xysum=x[L]*y[L];
		return;
	}
	int mid=(L+R)>>1;
	Build(loc<<1,L,mid);
	Build(loc<<1|1,mid+1,R);
	pushup(loc);
}
double calc(double x){
	return x*(x+1)*(2*x+1)/6;
}
void pushdown(int loc,int L,int R){
	int mid=(L+R)>>1;
	if(tree[loc].lazy2){
		double s=tree[loc].x2lazy,t=tree[loc].y2lazy;
		tree[loc<<1].lazy2=tree[loc<<1|1].lazy2=1;
		tree[loc<<1].x2lazy=tree[loc<<1|1].x2lazy=s;
		tree[loc<<1].y2lazy=tree[loc<<1|1].y2lazy=t;
		tree[loc<<1].x1lazy=tree[loc<<1|1].x1lazy=0;
		tree[loc<<1].y1lazy=tree[loc<<1|1].y1lazy=0;
		tree[loc<<1].lazy1=tree[loc<<1|1].lazy1=0;
		tree[loc].lazy2=0;tree[loc].x2lazy=tree[loc].y2lazy=0;
		tree[loc<<1].xsum=(mid-L+1)*1.0*(s+(mid+L)*0.5);
		tree[loc<<1].ysum=(mid-L+1)*1.0*(t+(mid+L)*0.5);
		tree[loc<<1].x2sum=calc(mid)-calc(L-1)+2*s*((mid-L+1)*1.0)*((mid+L)*0.5)+(mid-L+1)*s*s;
		tree[loc<<1].xysum=calc(mid)-calc(L-1)+(s+t)*((mid-L+1)*1.0)*((mid+L)*0.5)+(mid-L+1)*s*t;
		tree[loc<<1|1].xsum=(R-mid)*1.0*(s+(mid+R+1)*0.5);
		tree[loc<<1|1].ysum=(R-mid)*1.0*(t+(mid+R+1)*0.5);
		tree[loc<<1|1].x2sum=calc(R)-calc(mid)+2*s*((R-mid)*1.0)*((mid+R+1)*0.5)+(R-mid)*s*s;
		tree[loc<<1|1].xysum=calc(R)-calc(mid)+(s+t)*((R-mid)*1.0)*((mid+R+1)*0.5)+(R-mid)*s*t;
	}
	if(tree[loc].lazy1){
		double s=tree[loc].x1lazy,t=tree[loc].y1lazy;
		tree[loc<<1].x2sum+=2*s*tree[loc<<1].xsum+(mid-L+1)*s*s;
		tree[loc<<1].xysum+=t*tree[loc<<1].xsum+s*tree[loc<<1].ysum+(mid-L+1)*s*t;
		tree[loc<<1].xsum+=(mid-L+1)*s;
		tree[loc<<1].ysum+=(mid-L+1)*t;
		tree[loc<<1].x1lazy+=s;tree[loc<<1].y1lazy+=t;tree[loc<<1].lazy1=1;
		tree[loc<<1|1].x2sum+=2*s*tree[loc<<1|1].xsum+(R-mid)*s*s;
		tree[loc<<1|1].xysum+=t*tree[loc<<1|1].xsum+s*tree[loc<<1|1].ysum+(R-mid)*s*t;
		tree[loc<<1|1].xsum+=(R-mid)*s;
		tree[loc<<1|1].ysum+=(R-mid)*t;
		tree[loc<<1|1].x1lazy+=s;tree[loc<<1|1].y1lazy+=t;tree[loc<<1|1].lazy1=1;
		tree[loc].lazy1=0;tree[loc].x1lazy=0;tree[loc].y1lazy=0;
	}
}
void Update1(int loc,int L,int R,int l,int r,double s,double t){
	if(l<=L&&r>=R){
		tree[loc].x2sum+=2*s*tree[loc].xsum+(R-L+1)*s*s;
		tree[loc].xysum+=t*tree[loc].xsum+s*tree[loc].ysum+(R-L+1)*s*t;
		tree[loc].xsum+=(R-L+1)*s;
		tree[loc].ysum+=(R-L+1)*t;
		tree[loc].x1lazy+=s;
		tree[loc].y1lazy+=t;
		tree[loc].lazy1=1;
		return;
	}
	int mid=(L+R)>>1;
	pushdown(loc,L,R);
	if(r<=mid)Update1(loc<<1,L,mid,l,r,s,t);
	else if(l>mid)Update1(loc<<1|1,mid+1,R,l,r,s,t);
	else Update1(loc<<1,L,mid,l,mid,s,t),Update1(loc<<1|1,mid+1,R,mid+1,r,s,t);
	pushup(loc);
}
void Update2(int loc,int L,int R,int l,int r,double s,double t){
	if(l<=L&&r>=R){
		tree[loc].xsum=(R-L+1)*1.0*(s+(R+L)*0.5);
		tree[loc].ysum=(R-L+1)*1.0*(t+(R+L)*0.5);
		tree[loc].x2sum=calc(R)-calc(L-1)+2*s*((R-L+1)*1.0)*((R+L)*0.5)+(R-L+1)*s*s;
		tree[loc].xysum=calc(R)-calc(L-1)+(s+t)*((R-L+1)*1.0)*((R+L)*0.5)+(R-L+1)*s*t;
		tree[loc].lazy2=1;tree[loc].x2lazy=s;tree[loc].y2lazy=t;
		tree[loc].x1lazy=tree[loc].y1lazy=0;tree[loc].lazy1=0;
		return;
	}
	int mid=(L+R)>>1;
	pushdown(loc,L,R);
	if(r<=mid)Update2(loc<<1,L,mid,l,r,s,t);
	else if(l>mid)Update2(loc<<1|1,mid+1,R,l,r,s,t);
	else Update2(loc<<1,L,mid,l,mid,s,t),Update2(loc<<1|1,mid+1,R,mid+1,r,s,t);
	pushup(loc);
}
double Query_x(int loc,int L,int R,int l,int r){
	if(l<=L&&r>=R)return tree[loc].xsum;
	int mid=(L+R)>>1;
	pushdown(loc,L,R);
	if(r<=mid)return Query_x(loc<<1,L,mid,l,r);
	else if(l>mid)return Query_x(loc<<1|1,mid+1,R,l,r);
	else return Query_x(loc<<1,L,mid,l,mid)+Query_x(loc<<1|1,mid+1,R,mid+1,r);
}
double Query_y(int loc,int L,int R,int l,int r){
	if(l<=L&&r>=R)return tree[loc].ysum;
	int mid=(L+R)>>1;
	pushdown(loc,L,R);
	if(r<=mid)return Query_y(loc<<1,L,mid,l,r);
	else if(l>mid)return Query_y(loc<<1|1,mid+1,R,l,r);
	else return Query_y(loc<<1,L,mid,l,mid)+Query_y(loc<<1|1,mid+1,R,mid+1,r);
}
double Query_x2(int loc,int L,int R,int l,int r){
	if(l<=L&&r>=R)return tree[loc].x2sum;
	int mid=(L+R)>>1;
	pushdown(loc,L,R);
	if(r<=mid)return Query_x2(loc<<1,L,mid,l,r);
	else if(l>mid)return Query_x2(loc<<1|1,mid+1,R,l,r);
	else return Query_x2(loc<<1,L,mid,l,mid)+Query_x2(loc<<1|1,mid+1,R,mid+1,r);
}
double Query_xy(int loc,int L,int R,int l,int r){
	if(l<=L&&r>=R)return tree[loc].xysum;
	int mid=(L+R)>>1;
	pushdown(loc,L,R);
	if(r<=mid)return Query_xy(loc<<1,L,mid,l,r);
	else if(l>mid)return Query_xy(loc<<1|1,mid+1,R,l,r);
	else return Query_xy(loc<<1,L,mid,l,mid)+Query_xy(loc<<1|1,mid+1,R,mid+1,r);
}
void work(int L,int R){
	double xb=Query_x(1,1,n,L,R)/(1.0*(R-L+1)),yb=Query_y(1,1,n,L,R)/(1.0*(R-L+1));
	double xs=Query_x(1,1,n,L,R),ys=Query_y(1,1,n,L,R),x2s=Query_x2(1,1,n,L,R),xys=Query_xy(1,1,n,L,R);
	//printf("%.2f %.2f %.2f %.2f\n",xb,yb,x2s,xys);
	double ans=xys-yb*xs-xb*ys+xb*yb*(R-L+1);
	ans/=(x2s-2*xb*xs+(R-L+1)*xb*xb);
	printf("%.12f\n",ans);
}
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;
		double S,T;
		scanf("%d",&opt);
		//for(int i=1;i<=n;i++)
		//	printf("%.2f %.2f\n",Query_x(1,1,n,i,i),Query_y(1,1,n,i,i));
		//putchar(10);
		if(m==0)
			int a=1;
		if(opt==1)scanf("%d %d",&L,&R),work(L,R);
		if(opt==2)scanf("%d %d %lf %lf",&L,&R,&S,&T),Update1(1,1,n,L,R,S,T);
		if(opt==3)scanf("%d %d %lf %lf",&L,&R,&S,&T),Update2(1,1,n,L,R,S,T);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值