[BZOJ4821][SDOI2017]相关分析(线段树)

题目:

我是超链接

题解:

这个给的a的柿子很明显不好弄啊,我们画一画

a=Ri=L(xx¯)(yy¯)Ri=L(xx¯)2 a = ∑ i = L R ( x − x ¯ ) ( y − y ¯ ) ∑ i = L R ( x − x ¯ ) 2

(以后 表示 Ri=L ∑ i = L R
=(xyxy¯x¯y+x¯y¯)(x2+x¯22xx¯)=xyxy¯x¯y+x¯y¯x2+x¯22xx¯ = ∑ ( x y − x y ¯ − x ¯ y + x ¯ y ¯ ) ∑ ( x 2 + x ¯ 2 − 2 x x ¯ ) = ∑ x y − ∑ x y ¯ − ∑ x ¯ y + ∑ x ¯ y ¯ ∑ x 2 + ∑ x ¯ 2 − ∑ 2 x x ¯

然后再把 x¯y¯ x ¯ y ¯ 的柿子带进去
=xyxyrl+1xyrl+1+(rl+1)xy(rl+1)2x2+(x)2rl+12(x)2rl+1 = ∑ x y − ∑ x ∑ y r − l + 1 − ∑ x ∑ y r − l + 1 + ( r − l + 1 ) ∗ ∑ x ∑ y ( r − l + 1 ) 2 ∑ x 2 + ( ∑ x ) 2 r − l + 1 − 2 ( ∑ x ) 2 r − l + 1

=xyxyrl+1x2(x)2rl+1 = ∑ x y − ∑ x ∑ y r − l + 1 ∑ x 2 − ( ∑ x ) 2 r − l + 1

那么线段树我们需要维护的值是 xyxyx2 ∑ x y , ∑ x , ∑ y , ∑ x 2
然后区间修改画画柿子就好了
然后是几个注意点:数组都开成double吧,不然炸了精度
线段树的覆盖和增加是这样的:覆盖的时候把同一层的增加抹去,增加的时候如果同一层有覆盖标记,就直接累加到覆盖标记上。这样在pushdown的时候谁先谁后就无所谓了,因为只会存在一个

代码:

#include <cstdio>
#include <cstring>
using namespace std;
const double INF=1e9;
const int N=100005;
double sumxy[N*4],sumx[N*4],sumy[N*4],sumxf[N*4],allx[N*4],ally[N*4],deltax[N*4],deltay[N*4],x[N],y[N],sxy,sx,sy,sxf;
double Sum(double x){return x*(x+1.0)/2.0;}
double Sum2(double x){return x*(x+1.0)*(2.0*x+1.0)/6.0;}
void updata(int now)
{
    sumxy[now]=sumxy[now<<1]+sumxy[now<<1|1];
    sumx[now]=sumx[now<<1]+sumx[now<<1|1];
    sumy[now]=sumy[now<<1]+sumy[now<<1|1];
    sumxf[now]=sumxf[now<<1]+sumxf[now<<1|1];
}
void pushdown(int now,int l,int r,int mid)
{
    if (allx[now]!=INF || ally[now]!=INF)
    {
        sumxy[now<<1]=(mid-l+1.0)*allx[now]*ally[now]+(allx[now]+ally[now])*(Sum(mid)-Sum(l-1))+Sum2(mid)-Sum2(l-1);
        sumx[now<<1]=(mid-l+1.0)*allx[now]+Sum(mid)-Sum(l-1);
        sumy[now<<1]=(mid-l+1.0)*ally[now]+Sum(mid)-Sum(l-1);
        sumxf[now<<1]=(mid-l+1.0)*allx[now]*allx[now]+Sum2(mid)-Sum2(l-1)+2.0*allx[now]*(Sum(mid)-Sum(l-1));

        sumxy[now<<1|1]=(r-mid+0.0)*allx[now]*ally[now]+(allx[now]+ally[now])*(Sum(r)-Sum(mid))+Sum2(r)-Sum2(mid);
        sumx[now<<1|1]=(r-mid+0.0)*allx[now]+Sum(r)-Sum(mid);
        sumy[now<<1|1]=(r-mid+0.0)*ally[now]+Sum(r)-Sum(mid);
        sumxf[now<<1|1]=(r-mid+0.0)*allx[now]*allx[now]+Sum2(r)-Sum2(mid)+2.0*allx[now]*(Sum(r)-Sum(mid));

        allx[now<<1]=allx[now<<1|1]=allx[now];
        ally[now<<1]=ally[now<<1|1]=ally[now];
        allx[now]=INF; ally[now]=INF;
        deltax[now<<1]=deltax[now<<1|1]=0;
        deltay[now<<1]=deltay[now<<1|1]=0;
    }

    if (deltax[now] || deltay[now])
    {
        sumxf[now<<1]+=(mid-l+1.0)*deltax[now]*deltax[now]+sumx[now<<1]*2.0*deltax[now];
        sumxy[now<<1]+=deltay[now]*sumx[now<<1]+deltax[now]*sumy[now<<1]+(mid-l+1.0)*deltax[now]*deltay[now];
        sumx[now<<1]+=deltax[now]*(mid-l+1.0);
        sumy[now<<1]+=deltay[now]*(mid-l+1.0);
        if (allx[now<<1]!=INF || ally[now<<1]!=INF) allx[now<<1]+=deltax[now],ally[now<<1]+=deltay[now];
        else deltax[now<<1]+=deltax[now],deltay[now<<1]+=deltay[now];

        sumxf[now<<1|1]+=(r-mid+0.0)*deltax[now]*deltax[now]+sumx[now<<1|1]*2.0*deltax[now];
        sumxy[now<<1|1]+=deltay[now]*sumx[now<<1|1]+deltax[now]*sumy[now<<1|1]+(r-mid+0.0)*deltax[now]*deltay[now];
        sumx[now<<1|1]+=deltax[now]*(r-mid+0.0);
        sumy[now<<1|1]+=deltay[now]*(r-mid+0.0);
        if (allx[now<<1|1]!=INF || ally[now<<1|1]!=INF) allx[now<<1|1]+=deltax[now],ally[now<<1|1]+=deltay[now];
        else deltax[now<<1|1]+=deltax[now],deltay[now<<1|1]+=deltay[now];

        deltax[now]=0; deltay[now]=0;
    }
}
void build(int now,int l,int r)
{
    allx[now]=ally[now]=INF;
    if (l==r)
    {
        sumxy[now]=x[l]*y[l];sumx[now]=x[l];
        sumy[now]=y[l];sumxf[now]=x[l]*x[l];
        return;
    }
    int mid=(l+r)>>1;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    updata(now);
}
void add(int now,int l,int r,int lrange,int rrange,double s,double t)
{
    if (lrange<=l && rrange>=r) 
    {
        sumxf[now]+=(r-l+1.0)*s*s+sumx[now]*2.0*s;
        sumxy[now]+=t*sumx[now]+s*sumy[now]+(r-l+1.0)*s*t;
        sumx[now]+=s*(r-l+1.0);sumy[now]+=t*(r-l+1.0);
        if (allx[now]!=INF || ally[now]!=INF) allx[now]+=s,ally[now]+=t;
        else deltax[now]+=s,deltay[now]+=t;
        return;
    }
    int mid=(l+r)>>1;pushdown(now,l,r,mid);
    if (lrange<=mid) add(now<<1,l,mid,lrange,rrange,s,t);
    if (rrange>mid) add(now<<1|1,mid+1,r,lrange,rrange,s,t);
    updata(now);
}
void change(int now,int l,int r,int lrange,int rrange,double s,double t)
{
    if (lrange<=l && rrange>=r) 
    {
        sumxy[now]=(r-l+1.0)*s*t+(s+t)*(Sum(r)-Sum(l-1))+Sum2(r)-Sum2(l-1);
        sumx[now]=(r-l+1.0)*s+Sum(r)-Sum(l-1);
        sumy[now]=(r-l+1.0)*t+Sum(r)-Sum(l-1);
        sumxf[now]=(r-l+1.0)*s*s+Sum2(r)-Sum2(l-1)+2.0*s*(Sum(r)-Sum(l-1));
        allx[now]=s; ally[now]=t; deltax[now]=0; deltay[now]=0;
        return;
    }
    int mid=(l+r)>>1;pushdown(now,l,r,mid);
    if (lrange<=mid) change(now<<1,l,mid,lrange,rrange,s,t);
    if (rrange>mid) change(now<<1|1,mid+1,r,lrange,rrange,s,t);
    updata(now);
}
void qurry(int now,int l,int r,int lrange,int rrange)
{
    if (lrange<=l && rrange>=r) 
    {
        sxy+=sumxy[now]; sx+=sumx[now]; sy+=sumy[now];
        sxf+=sumxf[now];return;
    }
    int mid=(l+r)>>1;pushdown(now,l,r,mid);
    if (lrange<=mid) qurry(now<<1,l,mid,lrange,rrange);
    if (rrange>mid) qurry(now<<1|1,mid+1,r,lrange,rrange);
}
int main()
{
    int n,m;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 id,l,r;double s,t;
        scanf("%d%d%d",&id,&l,&r);
        if (id==1)
        {
            sxy=0;sx=0;sy=0;sxf=0;
            qurry(1,1,n,l,r);
            double ans=sxy-(sx*sy)*1.0/(r-l+1.0);
            ans/=sxf-(sx*sx)*1.0/(r-l+1.0);
            printf("%.10lf\n",ans);
        }
        else
        {
            scanf("%lf%lf",&s,&t);
            if (id==2) add(1,1,n,l,r,s,t);else change(1,1,n,l,r,s,t);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值