标签:cpp img load ref lazy hup term efi alt
啊,这道题目一点思路都没有啊。
这么神奇的吗。
就是死命的推式子,这里用一下这位大佬的证明。
当然,写这个博客主要是想讲一下维护平方和和区间加减。
首先,区间的\(lazy\)标记具有可加性:\((x+k+k)^2=(x+2k)^2\),因此,\(lazy\)标记可以叠加,只要计算每一个\(lazy\)标记会对维护的值产生多少的贡献即可。
非常的优秀呢。
因为用了别人太多证明了,所以用转载
#include<cstdio>
#include<cstring>
#define N 110000
#define NN 210000
using namespace std;
typedef double LL;
struct node
{
int l,r;//左右儿子
LL d,dx2,dxy,dx,dy,lx,ly;//d后面跟的就是维护的数值
int tl,tr;//维护区间
bool qin;//这个区间是否有被初始化过
}tr[NN];int len;
LL a[N],b[N];
inline void pushup(int x)
{
int lc=tr[x].l,rc=tr[x].r;
tr[x].dx=tr[lc].dx+tr[rc].dx;tr[x].dy=tr[lc].dy+tr[rc].dy;
tr[x].dxy=tr[lc].dxy+tr[rc].dxy;tr[x].dx2=tr[lc].dx2+tr[rc].dx2;
}
inline void pushlazy(int x,LL lx,LL ly)
{
tr[x].dx2+=tr[x].d*lx*lx+2*lx*tr[x].dx;
tr[x].dxy+=ly*tr[x].dx+lx*tr[x].dy+lx*ly*tr[x].d;
tr[x].dx+=lx*tr[x].d;tr[x].dy+=ly*tr[x].d;
tr[x].lx+=lx;tr[x].ly+=ly;
}
inline void pushqin(int x)
{
int l=tr[x].tl,r=tr[x].tr;
tr[x].lx=tr[x].ly=0;
tr[x].dx=tr[x].dy=(l+r)*tr[x].d/2;
tr[x].dxy=tr[x].dx2=(LL)r*(r+1)*(2*r+1)/6-(LL)(l-1)*l*(2*l-1)/6;
tr[x].qin=1;
}
inline void pushdown(int x)
{
if(tr[x].qin)
{
pushqin(tr[x].l);pushqin(tr[x].r);
tr[x].qin=0;
}
if(tr[x].lx || tr[x].ly)
{
pushlazy(tr[x].l,tr[x].lx,tr[x].ly);pushlazy(tr[x].r,tr[x].lx,tr[x].ly);
tr[x].lx=tr[x].ly=0;
}
}
void bt(int l,int r)
{
int now=++len;
tr[now].d=r-l+1;tr[now].tl=l;tr[now].tr=r;
if(l==r)tr[now].dx=a[l],tr[now].dx2=a[l]*a[l],tr[now].dxy=a[l]*b[l],tr[now].dy=b[l];
else
{
int mid=(l+r)/2;
tr[now].l=len+1;bt(l,mid);
tr[now].r=len+1;bt(mid+1,r);
pushup(now);
}
}
void change1(int now,int l,int r,int ll,int rr,LL lx,LL ly)/*非常单纯的修改*/
{
if(l==ll && r==rr){pushlazy(now,lx,ly);return ;}
int mid=(l+r)/2,lc=tr[now].l,rc=tr[now].r;
pushdown(now);
if(rr<=mid)change1(lc,l,mid,ll,rr,lx,ly);
else if(mid<ll)change1(rc,mid+1,r,ll,rr,lx,ly);
else change1(lc,l,mid,ll,mid,lx,ly),change1(rc,mid+1,r,mid+1,rr,lx,ly);
pushup(now);
}
void change2(int now,int l,int r,int ll,int rr)
{
if(l==ll && r==rr)
{
pushqin(now);
return ;
}
int mid=(l+r)/2,lc=tr[now].l,rc=tr[now].r;
pushdown(now);
if(rr<=mid)change2(lc,l,mid,ll,rr);
else if(mid<ll)change2(rc,mid+1,r,ll,rr);
else change2(lc,l,mid,ll,mid),change2(rc,mid+1,r,mid+1,rr);
pushup(now);
}
double ans_x,ans_y,ans_xy,ans_x2;
void findans(int now,int l,int r,int ll,int rr)
{
if(l==ll && r==rr)
{
ans_x+=tr[now].dx;ans_y+=tr[now].dy;
ans_xy+=tr[now].dxy;ans_x2+=tr[now].dx2;
return ;
}
int mid=(l+r)/2,lc=tr[now].l,rc=tr[now].r;
pushdown(now);
if(rr<=mid)findans(lc,l,mid,ll,rr);
else if(mid<ll)findans(rc,mid+1,r,ll,rr);
else findans(lc,l,mid,ll,mid),findans(rc,mid+1,r,mid+1,rr);
}
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%lf",&a[i]);
for(int i=1;i<=n;i++)scanf("%lf",&b[i]);
bt(1,n);
for(int i=1;i<=m;i++)
{
int type;scanf("%d",&type);
if(type==1)
{
int l,r;scanf("%d%d",&l,&r);
ans_x=ans_y=ans_xy=ans_x2=0;
findans(1,1,n,l,r);
printf("%lf\n",(ans_xy-ans_x*ans_y/(r-l+1))/(ans_x2-ans_x*ans_x/(r-l+1)));
}
else if(type==2)
{
int l,r;LL x,y;scanf("%d%d%lf%lf",&l,&r,&x,&y);
change1(1,1,n,l,r,x,y);
}
else if(type==3)
{
int l,r;LL x,y;scanf("%d%d%lf%lf",&l,&r,&x,&y);
change2(1,1,n,l,r);
change1(1,1,n,l,r,x,y);
}
}
return 0;
}
在遇到平均数的题目时们可以尝试把平均数拆开化化式子来做。
标签:cpp img load ref lazy hup term efi alt
原文地址:https://www.cnblogs.com/zhangjianjunab/p/13820150.html