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

拆开柿子之后 发现要维护 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值