P3707 [SDOI2017] 相关分析
题意
有两个序列 \(x,y\),修改有两种。
- \((l,r,S,T)\):对于所有 \(i\in[l,r]\),\(x_i\) 加上 \(S\),\(y_i\) 加上 \(T\)。
- \((l,r,S,T)\):对于所有 \(i\in[l,r]\),\(x_i\) 变成 \(S+i\),\(y_i\) 变成 \(T+o\)。
查询:令 \(\displaystyle\bar x=\frac1{r-l+1}sum_{i-l}^rx_i,\bar y=\frac1{r-l+1}sum_{i-l}^ry_i\),求\({\displaystyle\sum_{i=L} ^R (x_i-\overline{x})(y_i-\overline{y}) \over \displaystyle\sum _{i=L} ^R (x_i -\overline{x})^2}\)。
思路
\(\bar x\) 和 \(\bar y\) 是好求的,用个线段树维护即可。
考虑求 \(\sum_{i=L}^R(x_i-\bar x)(y_i-\bar y)\)。把祂拆开。
\[\begin{array}{lr}
=\sum_{i=L}^R(x_iy_i-\bar xy_i-\bar{y}x_i+\bar{x}\bar{y})\\
=\sum_{i=L}^Rx_iy_i-\bar x\sum_{i=L}^Ry_i-\bar y\sum_{i=L}^Rx_i+\bar x\bar y(R-L+1)
\end{array}
\]
都是好维护的。
考虑求 \(\sum_{i=L}^R(x_i-\bar x)^2\)。把祂拆开。
\[\begin{array}{lr}
=\sum_{i=L}^R(x_i^2+\bar x^2-2x_i\bar x)\\
=\sum_{i=L}^Rx_i^2+(R-L+1)\bar x^2-2\bar x\sum_{i=L}^Rx_i
\end{array}
\]
依然很好维护。
也就是说,线段树中需要维护 \(x,y,x^2,xy\)。
代码
/*
Luogu P3707 [SDOI2017] 相关分析
2026-04-09
*/
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
#define LL __int128
const int maxn=100010;
int n,m;
LL sum2[maxn];
LL calc(int l,int r){return 1ll*(l+r)*(r-l+1)/2;}
LL calc2(int l,int r){if(l==0) return sum2[r];return sum2[r]-sum2[l-1];}
class Segment_Tree{
private:
struct node{
LL x,y,x2,xy,lanS,lanT,lan2S,lan2T;
node(){lan2S=lan2T=-1;}
}t[maxn*8];
void add_tag1(int u,LL S,LL T,int l,int r){
LL sumx=t[u].x,sumy=t[u].y;
t[u].x+=(r-l+1)*S,t[u].y+=(r-l+1)*T;
t[u].xy+=sumx*T+sumy*S+(r-l+1)*S*T;
t[u].x2+=2*sumx*S+(r-l+1)*S*S;
t[u].lanS+=S,t[u].lanT+=T;
}
void add_tag2(int u,LL S,LL T,int l,int r){
t[u].lanS=t[u].lanT=0;
t[u].x=(r-l+1)*S+calc(l,r),t[u].y=(r-l+1)*T+calc(l,r);
t[u].xy=calc2(l,r)+calc(l,r)*(S+T)+(r-l+1)*S*T;
t[u].x2=calc2(l,r)+2*calc(l,r)*S+S*S*(r-l+1);
t[u].lan2S=S,t[u].lan2T=T;
}
void down(int u,int l,int r){
if(l==r) return ;
int mid=l+r>>1;
if(~t[u].lan2S) add_tag2(u<<1,t[u].lan2S,t[u].lan2T,l,mid);
add_tag1(u<<1,t[u].lanS,t[u].lanT,l,mid);
if(~t[u].lan2S) add_tag2(u<<1|1,t[u].lan2S,t[u].lan2T,mid+1,r);
add_tag1(u<<1|1,t[u].lanS,t[u].lanT,mid+1,r);
t[u].lan2S=t[u].lan2T=-1,t[u].lanS=t[u].lanT=0;
}
void push_up(int u){
t[u].x=t[u<<1].x+t[u<<1|1].x;
t[u].y=t[u<<1].y+t[u<<1|1].y;
t[u].x2=t[u<<1].x2+t[u<<1|1].x2;
t[u].xy=t[u<<1].xy+t[u<<1|1].xy;
}
void update1(int u,int l,int r,int ll,int rr,LL S,LL T){
if(l>rr||r<ll) return ;
if(ll<=l&&r<=rr){
add_tag1(u,S,T,l,r);
return ;
}
down(u,l,r);
int mid=l+r>>1;
update1(u<<1,l,mid,ll,rr,S,T),update1(u<<1|1,mid+1,r,ll,rr,S,T);
push_up(u);
}
void update2(int u,int l,int r,int ll,int rr,LL S,LL T){
if(l>rr||r<ll) return ;
if(ll<=l&&r<=rr){
add_tag2(u,S,T,l,r);
return ;
}
down(u,l,r);
int mid=l+r>>1;
update2(u<<1,l,mid,ll,rr,S,T),update2(u<<1|1,mid+1,r,ll,rr,S,T);
push_up(u);
}
tuple<LL,LL,LL,LL>add(tuple<LL,LL,LL,LL>a,tuple<LL,LL,LL,LL>b){return{get<0>(a)+get<0>(b),get<1>(a)+get<1>(b),get<2>(a)+get<2>(b),get<3>(a)+get<3>(b)};}
tuple<LL,LL,LL,LL>query(int u,int l,int r,int ll,int rr){
if(l>rr||r<ll) return{0,0,0,0};
if(ll<=l&&r<=rr) return{t[u].x,t[u].y,t[u].x2,t[u].xy};
down(u,l,r);
int mid=l+r>>1;
return add(query(u<<1,l,mid,ll,rr),query(u<<1|1,mid+1,r,ll,rr));
}
public:
void update1(int l,int r,int S,int T){update1(1,1,n,l,r,S,T);}
void update2(int l,int r,int S,int T){update2(1,1,n,l,r,S,T);}
double query(int l,int r){
auto[x,y,x2,xy]=query(1,1,n,l,r);
double xp=x*1.0/(r-l+1),yp=y*1.0/(r-l+1);
double up=xy-xp*y-yp*x+xp*yp*(r-l+1),dn=x2+(r-l+1)*xp*xp-2*xp*x;
return up/dn;
}
}t;
signed main(){
sum2[0]=0;
for(int i=1;i<=100000;i++) sum2[i]=sum2[i-1]+1ll*i*i;
read(n,m);
for(int i=1;i<=n;i++){
int S;read(S);
t.update1(i,i,S,0);
}
for(int i=1;i<=n;i++){
int T;read(T);
t.update1(i,i,0,T);
}
for(int i=1;i<=m;i++){
int op,l,r,S,T;read(op,l,r);
if(op==1) printf("%.10lf\n",t.query(l,r));
if(op==2){
read(S,T);
t.update1(l,r,S,T);
}
if(op==3){
read(S,T);
t.update2(l,r,S,T);
}
}
return 0;
}

浙公网安备 33010602011771号