[BZOJ4821][SDOI2017]相关分析
题意
你需要维护两个数组\(\{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;
}