[线段树] BZOJ 4821 [Sdoi2017]相关分析

xiaoxiao2021-02-27  187

拆开柿子之后 发现要维护 xi yi x2i xiyi 直接线段树就好了 两个标记合并的时候要注意下 一种可以覆盖另一种 似乎神犇有更短更快的方法?

#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; typedef double ld; const int N=100005; inline ld sum(int l,int r){ return (ld)(l+r)*(r-l+1)/2.0; } inline ld sum2(int n){ return (ld)n*(n+1)*(2*n+1)/6.0; } inline ld sum2(int l,int r){ return sum2(r)-sum2(l-1); } int n,m; ld _x[N],_y[N]; ld sx[N<<2],sy[N<<2],xy[N<<2],x2[N<<2]; ld f[N<<2],a[N<<2],b[N<<2],c[N<<2],d[N<<2]; inline void upd(int x){ sx[x]=sx[x<<1]+sx[x<<1|1],sy[x]=sy[x<<1]+sy[x<<1|1]; xy[x]=xy[x<<1]+xy[x<<1|1],x2[x]=x2[x<<1]+x2[x<<1|1]; } inline void Build(int x,int l,int r){ if (l==r){ sx[x]=_x[l],sy[x]=_y[l],xy[x]=_x[l]*_y[l],x2[x]=_x[l]*_x[l]; return; } int mid=(l+r)>>1; Build(x<<1,l,mid); Build(x<<1|1,mid+1,r); upd(x); } inline void mark(int x,int l,int r,ld _a,ld _b,ld _c,ld _d){ f[x]=1; a[x]=_a; b[x]=_b; c[x]=_c; d[x]=_d; sx[x]=_a*sum(l,r)+_b*(r-l+1),sy[x]=_c*sum(l,r)+_d*(r-l+1); x2[x]=_a*_a*sum2(l,r)+2*_a*_b*sum(l,r)+_b*_b*(r-l+1); xy[x]=_a*_c*sum2(l,r)+(_b*_c+_a*_d)*sum(l,r)+_b*_d*(r-l+1); } inline void mark(int x,int l,int r,ld dx,ld dy){ x2[x]+=2*sx[x]*dx+dx*dx*(r-l+1); xy[x]+=dx*sy[x]+dy*sx[x]+dx*dy*(r-l+1); sx[x]+=(r-l+1)*dx,sy[x]+=(r-l+1)*dy; b[x]+=dx,d[x]+=dy; if (!f[x]) f[x]=2; } inline void push(int x,int l,int r){ if (!f[x]) return; int mid=(l+r)>>1; if (f[x]==1){ mark(x<<1,l,mid,a[x],b[x],c[x],d[x]),mark(x<<1|1,mid+1,r,a[x],b[x],c[x],d[x]); }else if (f[x]==2){ mark(x<<1,l,mid,b[x],d[x]),mark(x<<1|1,mid+1,r,b[x],d[x]); } f[x]=a[x]=b[x]=c[x]=d[x]=0; } inline void Add(int x,int l,int r,int ql,int qr,ld dx,ld dy){ if (ql<=l && r<=qr){ mark(x,l,r,dx,dy); return; } push(x,l,r); int mid=(l+r)>>1; if (ql<=mid) Add(x<<1,l,mid,ql,qr,dx,dy); if (qr>mid) Add(x<<1|1,mid+1,r,ql,qr,dx,dy); upd(x); } inline void Modify(int x,int l,int r,int ql,int qr,ld a,ld b,ld c,ld d){ if (ql<=l && r<=qr){ mark(x,l,r,a,b,c,d); return; } push(x,l,r); int mid=(l+r)>>1; if (ql<=mid) Modify(x<<1,l,mid,ql,qr,a,b,c,d); if (qr>mid) Modify(x<<1|1,mid+1,r,ql,qr,a,b,c,d); upd(x); } ld SX,SY,X2,XY; inline void Query(int x,int l,int r,int ql,int qr){ if (ql<=l && r<=qr){ SX+=sx[x]; SY+=sy[x]; X2+=x2[x]; XY+=xy[x]; return; } push(x,l,r); int mid=(l+r)>>1; if (ql<=mid) Query(x<<1,l,mid,ql,qr); if (qr>mid) Query(x<<1|1,mid+1,r,ql,qr); } int main(){ int order,l,r; double a,b; freopen("t.in","r",stdin); freopen("t.out","w",stdout); scanf("%d%d",&n,&m); double tt; for (int i=1;i<=n;i++) scanf("%lf",&tt),_x[i]=tt; for (int i=1;i<=n;i++) scanf("%lf",&tt),_y[i]=tt; Build(1,1,n); while (m--){ scanf("%d%d%d",&order,&l,&r); if (order==1){ SX=SY=X2=XY=0; Query(1,1,n,l,r); printf("%.10lf\n",(double)((XY-SX*SY/(r-l+1))/(X2-SX*SX/(r-l+1)))); }else if (order==2){ scanf("%lf%lf",&a,&b); Add(1,1,n,l,r,a,b); }else if (order==3){ scanf("%lf%lf",&a,&b); Modify(1,1,n,l,r,1,a,1,b); } } return 0; }
转载请注明原文地址: https://www.6miu.com/read-13183.html

最新回复(0)