1. 程式人生 > >[BZOJ4821][SDOI2017]相關分析

[BZOJ4821][SDOI2017]相關分析

algorithm www. IT struct www amp tdi code clu

bzoj
luogu

題意

你需要維護兩個數組\(\{x_i\},\{y_i\}\),資瓷一下三種操作。
1、給出\(l,r\),設\(\overline x,\overline y\)分別表示區間\([l,r]\)\(x_i,y_i\)的平均數,求:
\[\frac{\sum_{i=l}^r(x_i-\overline x)(y_i-\overline y)}{\sum_{i=l}^r(x_i-\overline x)^2}\]
2、給出\(l,r,S,T\),令區間\([l,r]\)內每個\(x_i+=S,y_i+=T\)
3、給出\(l,r,S,T\),令區間\([l,r]\)內每個\(x_i=S+i,y_i=i+T\)

sol

把詢問式的括號拆了,利用\(\overline x*(r-l+1)=\sum_{i=l}^rx_i\)化簡一下式子:
\[\frac{\sum x_iy_i+\frac 1{r-l+1}\sum x_i*\sum y_i}{\sum x_i^2+\frac 1{r-l+1}\sum x_i*\sum x_i}\]
所以只要維護區間的\(\sum x,\sum y,\sum xy,\sum x^2\)就行了。
操作2是一個區間加,有:
\(\sum(x+\Delta x)(y+\Delta y)=\sum xy+\sum x*\Delta y+\sum y*\Delta x+(r-l+1)*\Delta x*\Delta y\)


操作3可以看作是先把區間變成\(x_i=y_i=i\)再做一次2操作。
區間覆蓋的時候要把操作2的\(lazy\)清空。
\(\sum_{i=1}^{n}i=\frac 12n*(n+1)\)
\(\sum_{i=1}^{n}i^2=\frac 16n*(n+1)*(2n+1)\)

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5+5;
int n,m,tag_c[N<<2];double X[N],Y[N],tag_x[N<<2],tag_y[N<<2
]; struct data{double x,y,xy,xx;}t[N<<2]; data operator + (data a,data b){ return (data){a.x+b.x,a.y+b.y,a.xy+b.xy,a.xx+b.xx}; } void build(int x,int l,int r){ if (l==r){ t[x].x=X[l];t[x].y=Y[l]; t[x].xy=t[x].x*t[x].y;t[x].xx=t[x].x*t[x].x; return; } int mid=l+r>>1; build(x<<1,l,mid);build(x<<1|1,mid+1,r); t[x]=t[x<<1]+t[x<<1|1]; } void cover1(int x,int l,int r,double S,double T){ double len=r-l+1; t[x].xy+=t[x].x*T+t[x].y*S+S*T*len; t[x].xx+=2*t[x].x*S+S*S*len; t[x].x+=S*len;t[x].y+=T*len; tag_x[x]+=S;tag_y[x]+=T; } double cal1(int x){return (double)x*(x+1)/2;} double cal2(int x){return (double)x*(x+1)*(2*x+1)/6;} void cover2(int x,int l,int r){ t[x].x=t[x].y=cal1(r)-cal1(l-1); t[x].xy=t[x].xx=cal2(r)-cal2(l-1); tag_c[x]=1;tag_x[x]=tag_y[x]=0; } void pushdown(int x,int l,int r){ int mid=l+r>>1; if (tag_c[x]){ cover2(x<<1,l,mid);cover2(x<<1|1,mid+1,r); tag_c[x]=0; } if (tag_x[x]||tag_y[x]){ cover1(x<<1,l,mid,tag_x[x],tag_y[x]); cover1(x<<1|1,mid+1,r,tag_x[x],tag_y[x]); tag_x[x]=tag_y[x]=0; } } void modify1(int x,int l,int r,int ql,int qr,double S,double T){ if (l>=ql&&r<=qr) {cover1(x,l,r,S,T);return;} pushdown(x,l,r);int mid=l+r>>1; if (ql<=mid) modify1(x<<1,l,mid,ql,qr,S,T); if (qr>mid) modify1(x<<1|1,mid+1,r,ql,qr,S,T); t[x]=t[x<<1]+t[x<<1|1]; } void modify2(int x,int l,int r,int ql,int qr){ if (l>=ql&&r<=qr) {cover2(x,l,r);return;} pushdown(x,l,r);int mid=l+r>>1; if (ql<=mid) modify2(x<<1,l,mid,ql,qr); if (qr>mid) modify2(x<<1|1,mid+1,r,ql,qr); t[x]=t[x<<1]+t[x<<1|1]; } data query(int x,int l,int r,int ql,int qr){ if (l>=ql&&r<=qr) return t[x]; pushdown(x,l,r);int mid=l+r>>1; if (qr<=mid) return query(x<<1,l,mid,ql,qr); if (ql>mid) return query(x<<1|1,mid+1,r,ql,qr); return query(x<<1,l,mid,ql,qr)+query(x<<1|1,mid+1,r,ql,qr); } int main(){ 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 opt,l,r;scanf("%d%d%d",&opt,&l,&r); if (opt==1){ data ans=query(1,1,n,l,r); double p=ans.xy-ans.x*ans.y/(r-l+1); double q=ans.xx-ans.x*ans.x/(r-l+1); printf("%.10lf\n",p/q); }else{ double S,T;scanf("%lf%lf",&S,&T); if (opt==3) modify2(1,1,n,l,r); modify1(1,1,n,l,r,S,T); } } return 0; }

[BZOJ4821][SDOI2017]相關分析