• Luogu P3707 [SDOI2017]相关分析


    题意

    给定两个长度为 (n) 的序列 (x,y),有 (m) 次操作,每次操作形如以下三种:

    • 1 l r:求出 ((x_l,y_l),cdots,(x_r,y_r)) 的回归方程的斜率。

    • 2 l r S T:将满足 (lleq ileq r)(x_i) 加上 (S)(y_i) 加上 (T)

    • 3 l r S T:将满足 (lleq ileq r)(x_i) 改为 (S+i)(y_i) 改为 (T+i)

    其中对于数据 ((x_1,y_1),cdots (x_n,y_n)) 的回归方程的斜率为

    [hat{a}=frac{sumlimits_{i=1}^{n}(x_i-overline{x})(y_i-overline{y})}{sumlimits_{i=1}^{n}(x_i-overline{x})^2} ]

    ( exttt{Data Range:}1leq n,mleq 10^5)

    题解

    写了两个小时,线段树懒标记部分写错都不知道自己是怎么死的。

    mmp 这题怎么这么难写

    考虑先推一下式子,强行展开有

    [hat{a}=frac{sumlimits_{i=1}^{n}x_iy_i-overline{x}sumlimits_{i=1}^{n}y_i-overline{y}sumlimits_{i=1}^{n}x_i+noverline{x}overline{y}}{sumlimits_{i=1}^{n}x_i^2-2overline{x}sumlimits_{i=1}^{n}x_i+noverline{x}^2} ]

    考虑将 (overline{x})(overline{y}) 拆一下并且合并一下同类项得到

    [hat{a}=frac{sumlimits_{i=1}^{n}x_iy_i-frac{1}{n}sumlimits_{i=1}^{n}x_isumlimits_{i=1}^{n}y_i}{sumlimits_{i=1}^{n}x_i^2-frac{1}{n}sumlimits_{i=1}^{n}x_i} ]

    到这里维护的东西就很清晰了,考虑怎么来维护。一次的东西很平凡,考虑二次的。

    [sumlimits_{i=1}^{n}(x_i+S)(y_i+T)=sumlimits_{i=1}^{n}x_iy_i+Ssumlimits_{i=1}^{n}y_i+Tsumlimits_{i=1}^{n}x_i+nST ]

    然后就没了,同样的道理得到

    [sumlimits_{i=1}^{n}(x_i+S)^2=sumlimits_{i=1}^{n}x_i^2+2Ssumlimits_{i=1}^{n}x_i+nS^2 ]

    这样就可以直接做 (2) 操作了。对于 (3) 操作的话可以先考虑强行赋值然后再区间加,赋值这一部分就是基础的求和公式运用,然后就没了。

    一个注意的点是区间赋值递归到某个区间时要把这个区间的加法懒标记清零(我这个 sb 就是因为这个调了 1h 的

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef int ll;
    typedef long long int li;
    typedef long double db;
    const ll MAXN=2e5+51;
    struct SegmentTree{
        ll l,r,tag;
        db sxx,sxy,sx,sy,tagx,tagy;
    };
    SegmentTree tree[MAXN<<2];
    ll n,qcnt,op,l,r,len;
    SegmentTree p,g;
    db s,t;
    db x[MAXN],y[MAXN];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    inline db sum2(ll x)
    {
        return 1.0*x*(x+1)*(2*x+1)/6;
    }
    #define ls node<<1
    #define rs (node<<1)|1
    inline void update(ll node)
    {
        tree[node].sxx=tree[ls].sxx+tree[rs].sxx;
        tree[node].sxy=tree[ls].sxy+tree[rs].sxy;
        tree[node].sx=tree[ls].sx+tree[rs].sx;
        tree[node].sy=tree[ls].sy+tree[rs].sy;
    }
    inline void create(ll l,ll r,ll node)
    {
        tree[node]=(SegmentTree){l,r};
        if(l==r)
        {
            tree[node].sx=x[l],tree[node].sy=y[l];
            return (void)(tree[node].sxx=x[l]*x[l],tree[node].sxy=x[l]*y[l]);
        }
        ll mid=(tree[node].l+tree[node].r)>>1;
        create(l,mid,ls),create(mid+1,r,rs),update(node);
    }
    inline void spread(ll node)
    {
        ll lenl=tree[ls].r-tree[ls].l+1,lenr=tree[rs].r-tree[rs].l+1;
        if(tree[node].tag)
        {
            tree[ls].sx=tree[ls].sy=lenl*tree[ls].l+lenl*(lenl-1)/2.0;
            tree[rs].sx=tree[rs].sy=lenr*tree[rs].l+lenr*(lenr-1)/2.0;
            tree[ls].sxx=tree[ls].sxy=sum2(tree[ls].r)-sum2(tree[ls].l-1);
            tree[rs].sxx=tree[rs].sxy=sum2(tree[rs].r)-sum2(tree[rs].l-1);
            tree[ls].tag=tree[rs].tag=1,tree[node].tag=0;
            tree[ls].tagx=tree[ls].tagy=tree[rs].tagx=tree[rs].tagy=0;
        }
        if(tree[node].tagx!=0||tree[node].tagy!=0)
        {
            db u=tree[node].tagx,v=tree[node].tagy;
            tree[ls].sxx+=2*u*tree[ls].sx+lenl*u*u;
            tree[rs].sxx+=2*u*tree[rs].sx+lenr*u*u;
            tree[ls].sxy+=u*tree[ls].sy+v*tree[ls].sx+lenl*u*v;
            tree[rs].sxy+=u*tree[rs].sy+v*tree[rs].sx+lenr*u*v;
            tree[ls].sx+=lenl*u,tree[ls].sy+=lenl*v;
            tree[rs].sx+=lenr*u,tree[rs].sy+=lenr*v;
            tree[ls].tagx+=u,tree[rs].tagx+=u,tree[node].tagx=0;
            tree[ls].tagy+=v,tree[rs].tagy+=v,tree[node].tagy=0;
        }
    }
    inline void add(ll l,ll r,db s,db t,ll node)
    {
        if(l<=tree[node].l&&r>=tree[node].r)
        {
            ll len=tree[node].r-tree[node].l+1;
            tree[node].sxx+=2*s*tree[node].sx+len*s*s;
            tree[node].sxy+=s*tree[node].sy+t*tree[node].sx+len*s*t;
            tree[node].sx+=len*s,tree[node].sy+=len*t;
            return (void)(tree[node].tagx+=s,tree[node].tagy+=t);
        }
        ll mid=(tree[node].l+tree[node].r)>>1;
        spread(node),l<=mid?add(l,r,s,t,ls):(void)1,r>mid?add(l,r,s,t,rs):(void)1;
        update(node);
    }
    inline void cover(ll l,ll r,ll node)
    {
        if(l<=tree[node].l&&r>=tree[node].r)
        {
            ll len=tree[node].r-tree[node].l+1;
            tree[node].sxx=tree[node].sxy=sum2(tree[node].r)-sum2(tree[node].l-1);
            tree[node].sx=tree[node].sy=tree[node].l*len+len*(len-1)/2.0;
            return (void)(tree[node].tag=1,tree[node].tagx=tree[node].tagy=0);
        }
        ll mid=(tree[node].l+tree[node].r)>>1;
        spread(node),l<=mid?cover(l,r,ls):(void)1,r>mid?cover(l,r,rs):(void)1;
        update(node);
    }
    inline SegmentTree query(ll l,ll r,ll node)
    {
        SegmentTree u=g,v=g;
        if(l<=tree[node].l&&r>=tree[node].r)
        {
            return tree[node];    
        }    
        ll mid=(tree[node].l+tree[node].r)>>1;
        spread(node);
        l<=mid?(void)(u=query(l,r,ls)):(void)1;
        r>mid?(void)(v=query(l,r,rs)):(void)1;
        return (SegmentTree){0,0,0,u.sxx+v.sxx,u.sxy+v.sxy,u.sx+v.sx,u.sy+v.sy};
    }
    int main()
    {
        n=read(),qcnt=read();
        for(register int i=1;i<=n;i++)
        {
            scanf("%Lf",&x[i]);
        }
        for(register int i=1;i<=n;i++)
        {
            scanf("%Lf",&y[i]);
        }
        create(1,n,1);
        for(register int i=1;i<=qcnt;i++)
        {
            op=read(),l=read(),r=read();
            if(op==1)
            {
                p=query(l,r,1),len=r-l+1;
                printf("%.10Lf
    ",(p.sxy-p.sx*p.sy/len)/(p.sxx-p.sx*p.sx/len));
                continue;
            }
            scanf("%Lf%Lf",&s,&t),op==3?cover(l,r,1):(void)1,add(l,r,s,t,1);
        }
    }
    
  • 相关阅读:
    13.解决SUSELinux用户登录Module is unknow问题
    12.解决SUSE Linux无法使用SSH登录的问题
    11.SUSE Linux服务器系统网卡配置重启问题
    02.Windows2012R2安装360安全卫士失败及无法卸载问题
    01.Windows2008R2系统禁启SMBv1服务命令
    07.SUSE Linux 系统本地yum源配置
    06.Linux-RedHat系统本地yum源配置
    05.Linux-CentOS系统本地Yum源搭建
    04.Linux-CentOS系统sudo权限配置
    03.LinuxCentOS系统root目录LVM磁盘扩容
  • 原文地址:https://www.cnblogs.com/Karry5307/p/13682106.html
Copyright © 2020-2023  润新知