[sdoi2017][bzoj4821] D2T3 相关分析

4821
就是维护回归方程
a=sigma(xy)-n_x_y/sigma(x^2)-n_x^2

发现等差数列有点难写,所以将每个位置上的数变换为i+x i+y形式,然后操作2变成区间加,操作3变成区间覆盖。
操作2 i+x+S i+y+T

对于xy,注意这里提到的x,y全部都是原来的x,y
(x+i)*(y+i)=xy+xi+iy+ii
(x+S+i)*(y+T+i)=xy+xT+xi+Sy+ST+Si+iy+iT+ii
增加了
xT+Sy +ST +Si+iT

Si+iT+ST可以O1,预处理出每个区间的sumi,即该区间i的和
i(S+T)+ST,分配律一下

xT+Sy
对于每一个数增加了xT+Sy
对于区间x1T+x2T+Sy1+Sy2….
T(x1+x2….)+S(y1+y2…..)
考虑维护sigma(x)and sigma(y)
T(sigma(x))+S(sigma(y))

n_x_y维护sigma(x)and sigma(y)

x+S
(i+x)^2=ii+2ix+xx
(i+x+S)^2=(i+x+S)(i+x+S)
=ii+ix+iS+xi+xx+xS+Si+Sx+SS
=ii+2ix+2iS+xx+2xS+SS

sigma(x^2)每个数增加了 2*S(i+x)+SS
2*S(sumi+sumx)

对于操作3

(x+i)*(y+i)=xy+xi+iy+ii
预处理i^2的前缀和,x,y是区间覆盖传下来的,O1处理

(i+x)^2=ii+2ix+xx
同样

所以就能O1维护了

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define db double
using namespace std;
int n,m;
const int N=1e5+7;
const int M=1e6+7;
bool tag[M];
double X[N],Y[N],xy[M],sumx[M],sumy[M],sqrx[M],tot[M],sumi[M],sqri[N],add_x[M],add_y[M];
struct Pair
{
    double xy,sumx,sumy,sqrx;
};
Pair operator +(Pair a,Pair b)
{
    return (Pair){a.xy+b.xy,a.sumx+b.sumx,a.sumy+b.sumy,a.sqrx+b.sqrx};
}
inline void updata(int k)
{
    int l=k<<1,r=k<<1|1;
    xy[k]=xy[l]+xy[r];
    sumx[k]=sumx[l]+sumx[r];
    sumy[k]=sumy[l]+sumy[r];
    sqrx[k]=sqrx[l]+sqrx[r];
} 
inline void build(int k,int l,int r)
{
    int mid=l+r>>1;
    tot[k]=r-l+1;
    sumi[k]=(l*2+tot[k]-1)*tot[k]/2;
    if(l==r)
    {
        sumx[k]=X[l]-l;
        sumy[k]=Y[l]-l;
        sqrx[k]=(db)X[l]*X[l];
        xy[k]=(db)X[l]*Y[l];
        return;
    }
    build(k*2,l,mid);
    build(k*2+1,mid+1,r);
    updata(k);
}
inline void modify(int k,int l,int r,db S,db T)
{
    tag[k]=1;
    xy[k]=sumi[k]*(S+T)+(sqri[r]-sqri[l-1])+S*T*tot[k];
    sumx[k]=S*tot[k];
    sumy[k]=T*tot[k];
    sqrx[k]=S*S*tot[k]+(sqri[r]-sqri[l-1])+2*S*sumi[k];
    add_x[k]=S;
    add_y[k]=T;
}
inline void uptags(int k,int L,db S,db T)
{
    xy[k]+=(S+T)*sumi[k]+S*T*tot[k]+T*sumx[k]+S*sumy[k];
    sqrx[k]+=S*S*tot[k]+S*2*(sumi[k]+sumx[k]);
    add_x[k]+=S;
    add_y[k]+=T;
    sumx[k]+=tot[k]*S;
    sumy[k]+=tot[k]*T;
}
inline void pushdown(int x,int L,int R)
{
    int l=x<<1,r=x<<1|1,mid=L+R>>1;
    if(tag[x])
    {
        modify(l,L,mid,add_x[x],add_y[x]);
        modify(r,mid+1,R,add_x[x],add_y[x]);
        add_x[x]=add_y[x]=0;
        tag[x]=0;
        return;
    }
    if(add_x[x]||add_y[x])
    {
        uptags(l,L,add_x[x],add_y[x]);
        uptags(r,mid+1,add_x[x],add_y[x]);
        add_x[x]=add_y[x]=0;
    }
}
inline void cover(int k,int l,int r,int x,int y,db S,db T)
{
    int mid=l+r>>1;
    if(x<=l&&r<=y)
    {
        modify(k,l,r,S,T);
        return;
    }
    pushdown(k,l,r);
    if(x<=mid) cover(k*2,l,mid,x,y,S,T);
    if(y> mid) cover(k*2+1,mid+1,r,x,y,S,T);
    updata(k);
}
inline void add(int k,int l,int r,int x,int y,db S,db T)
{
    int mid=l+r>>1;
    if(x<=l&&r<=y)
    {
        uptags(k,l,S,T);
        return;
    }
    pushdown(k,l,r);
    if(x<=mid) add(k*2,l,mid,x,y,S,T);
    if(y> mid) add(k*2+1,mid+1,r,x,y,S,T);
    updata(k);
}
inline Pair query(int k,int l,int r,int x,int y)
{
    int mid=l+r>>1;
    Pair res=(Pair){0,0};
    if(x<=l&&r<=y) return (Pair){xy[k],sumx[k]+sumi[k],sumy[k]+sumi[k],sqrx[k]};
    pushdown(k,l,r);
    if(x<=mid) res=res+query(k*2,l,mid,x,y);
    if(y> mid) res=res+query(k*2+1,mid+1,r,x,y);
    return res;
}
int main()
{
//  freopen("relative.in","r",stdin);
//  freopen("relative.out","w",stdout);
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%lf",&X[i]);
    for(int i=1;i<=n;i++)scanf("%lf",&Y[i]);
    for(int i=1;i<=n;++i) sqri[i]+=sqri[i-1]+(db)i*i;
    build(1,1,n);
    int flag;
    double len,l,r,S,T;
    Pair k;
    for(int i=1;i<=m;++i)
    {
        scanf("%d%lf%lf",&flag,&l,&r);
        if(flag==1)
        {
            k=query(1,1,n,l,r);
            len=r-l+1;
            printf("%.10lf\n",(k.xy-k.sumx*k.sumy/(db)len)/(k.sqrx-k.sumx*k.sumx/(db)len));
        }
        if(flag==2)
        {
            scanf("%lf%lf",&S,&T);
            add(1,1,n,l,r,S,T);
        }
        if(flag==3)
        {
            scanf("%lf%lf",&S,&T);
            cover(1,1,n,l,r,S,T);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值