Description
Frank对天文学非常感兴趣,他经常用望远镜看星星,同时记录下它们的信息,比如亮度、颜色等等,进而估算出
星星的距离,半径等等。Frank不仅喜欢观测,还喜欢分析观测到的数据。他经常分析两个参数之间(比如亮度和
半径)是否存在某种关系。现在Frank要分析参数X与Y之间的关系。他有n组观测数据,第i组观测数据记录了x_i和
y_i。他需要一下几种操作1 L,R:用直线拟合第L组到底R组观测数据。用xx表示这些观测数据中x的平均数,用yy
表示这些观测数据中y的平均数,即
xx=Σx_i/(R-L+1)(L<=i<=R)
yy=Σy_i/(R-L+1)(L<=i<=R)
如果直线方程是y=ax+b,那么a应当这样计算:
a=(Σ(x_i-xx)(y_i-yy))/(Σ(x_i-xx)(x_i-xx)) (L<=i<=R)
你需要帮助Frank计算a。
2 L,R,S,T:
Frank发现测量数据第L组到底R组数据有误差,对每个i满足L <= i <= R,x_i需要加上S,y_i需要加上T。
3 L,R,S,T:
Frank发现第L组到第R组数据需要修改,对于每个i满足L <= i <= R,x_i需要修改为(S+i),y_i需要修改为(T+i)。
Input
第一行两个数n,m,表示观测数据组数和操作次数。
接下来一行n个数,第i个数是x_i。
接下来一行n个数,第i个数是y_i。
接下来m行,表示操作,格式见题目描述。
1<=n,m<=10^5,0<=|S|,|T|,|x_i|,|y_i|<=10^5
保证1操作不会出现分母为0的情况。
Output
对于每个1操作,输出一行,表示直线斜率a。
选手输出与标准输出的绝对误差不超过10^-5即为正确。
Sample Input
3 5
1 2 3
1 2 3
1 1 3
2 2 3 -3 2
1 1 2
3 1 2 2 1
1 1 3
Sample Output
1.0000000000
-1.5000000000
-0.6153846154
HINT
Source
对于询问,十分难受,将它化简。
∑ri=l(xi−x¯)(yi−y¯)∑ri=l(xi−x¯)2
∑ri=lxi∗yi−x¯∑ri=lyi−y¯∑ri=lxi−(r−l+1)∗x¯∗y¯∑ri=lx2i−2∗x¯∗∑ri=lxi+(r−l+1)∗x¯2
令
len=r−l+1
x¯=∑ri=lxilen
y¯=∑ri=lyilen
len∗∑ri=lxi∗yi−∑ri=lxi∗∑ri=lyilen∗∑ri=lx2i−(∑ri=lxi)2
可以看出只需要维护 ∑xi∗yi , ∑xi , ∑yi , ∑x2i
做出一棵线段树,2操作较简单,3操作可以看作先覆盖,再进行2操作。
注意标记下传的时候,先检查是否有覆盖标记,如果有将加法标记清除。
更新覆盖标记时,需要运用数列求和的姿势,注意要开double,防止溢出。
#include<iostream>
#include<cstdio>
#define lc num<<1
#define rc num<<1|1
using namespace std;
const int N=100005;
int n,m;
double xx[N],yy[N];
struct segtree
{
int l,r,len;
double sum[5],tagx,tagy;
bool chg;
//1 x 2 y 3 x2 4 xy
}st[4*N];
void update1(int num,double s,double t)
{
st[num].sum[3]+=2*s*st[num].sum[1]+st[num].len*s*s;
st[num].sum[4]+=s*st[num].sum[2]+t*st[num].sum[1]+st[num].len*s*t;
st[num].sum[1]+=st[num].len*s;
st[num].sum[2]+=st[num].len*t;
st[num].tagx+=s,st[num].tagy+=t;
}
void update2(int num)
{
st[num].sum[2]=st[num].sum[1]=((double)(st[num].r+st[num].l)*st[num].len)/2;
st[num].sum[3]=st[num].sum[4]=((double)st[num].r*(st[num].r+1)*(2*st[num].r+1)-(double)(st[num].l-1)*st[num].l*(2*st[num].l-1))/6;
st[num].chg=1;
st[num].tagx=st[num].tagy=0;
}
void pushup(int num)
{
for(int i=1;i<=4;i++)
st[num].sum[i]=st[lc].sum[i]+st[rc].sum[i];
}
void pushdown(int num)
{
if(st[num].chg)
{
if(st[num].l!=st[num].r)
update2(lc),update2(rc);
st[num].chg=0;
}
if(st[num].tagx!=0||st[num].tagy!=0)//区间加法
{
if(st[num].l!=st[num].r)
update1(lc,st[num].tagx,st[num].tagy),update1(rc,st[num].tagx,st[num].tagy);
st[num].tagx=st[num].tagy=0;
}
}
void build(int num,int l,int r)
{
st[num].l=l,st[num].r=r,st[num].len=r-l+1;
if(l==r)
{
st[num].sum[1]=xx[l],st[num].sum[2]=yy[l];
st[num].sum[3]=xx[l]*xx[l],st[num].sum[4]=xx[l]*yy[l];
return ;
}
int mid=l+r>>1;
build(lc,l,mid),build(rc,mid+1,r);
pushup(num);
}
void add(int num,int x,int y,double s,double t)//区间加法
{
if(st[num].l>=x&&st[num].r<=y)
{
update1(num,s,t);
return ;
}
pushdown(num);
if(x<=st[lc].r)
add(lc,x,y,s,t);
if(y>=st[rc].l)
add(rc,x,y,s,t);
pushup(num);
}
void change(int num,int x,int y)//将第i个数改为i
{
if(st[num].l>=x&&st[num].r<=y)
{
update2(num);
return ;
}
pushdown(num);
if(x<=st[lc].r)
change(lc,x,y);
if(y>=st[rc].l)
change(rc,x,y);
pushup(num);
}
double query(int num,int x,int y,int z)
{
if(st[num].l>=x&&st[num].r<=y)
return st[num].sum[z];
pushdown(num);
double res=0;
if(x<=st[lc].r)
res+=query(lc,x,y,z);
if(y>=st[rc].l)
res+=query(rc,x,y,z);
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lf",&xx[i]);
for(int i=1;i<=n;i++)
scanf("%lf",&yy[i]);
build(1,1,n);
int k,l,r;
double x,y;
while(m--)
{
scanf("%d%d%d",&k,&l,&r);
if(k==1)
{
double res1=query(1,l,r,1),res2=query(1,l,r,2),res3=query(1,l,r,3),res4=query(1,l,r,4);
int len=r-l+1;
printf("%f\n",(len*res4-res1*res2)/(len*res3-res1*res1));
}
else
{
scanf("%lf%lf",&x,&y);
if(k==3)
change(1,l,r);
add(1,l,r,x,y);
}
}
return 0;
}