题目链接: 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(xi−xˉ)2∑LR(xi−xˉ)(yi−yˉ)有三个操作分别是求区间 [ 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}) (L≤i≤R)
题目分析: 这个题看起来不难,但是一看就麻烦的要死;我们先把
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(xi2−2xixˉ+xˉ2)∑LRxiyi−∑LRxiyˉ然后就可以考虑通过线段树维护这个式子了,我们需要维护的量有
∑
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
t∑LRx+s∑LRy+(R−L+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;
}