这题用 ZKW 线段树的永久懒标记写挺抽象的。
#include<bits/stdc++.h>
#define putchar putchar_unlocked
#define getchar getchar_unlocked
using namespace std;
template<typename T>
void read(T &x){x=0;char ch=getchar();while(!isdigit(ch)){ch=getchar();}while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();}}
template<typename T>
void print(const T &x){if(x>9){print(x/10);}putchar(x%10|0x30);}
template<typename T>
void printcs(const T &x){if(x<0){putchar('-');print(-x);}else{print(x);}putchar(' ');}
template<typename T>
void println(const T &x){if(x<0){putchar('-');print(-x);}else{print(x);}putchar('\n');}
const int N = 1e5+10;
typedef double Type;
struct node{
Type v,vv,tag;
}tr[N<<4];
int m;
inline void build(const int &n){
for(m=1;m<=n;m<<=1);
for(int i = m+1;i<=m+n;++i)scanf("%lf",&tr[i].v),tr[i].vv = tr[i].v*tr[i].v;
for(int i = m-1;i;--i)tr[i].v=tr[i<<1].v+tr[i<<1|1].v,tr[i].vv = tr[i<<1].vv+tr[i<<1|1].vv;
}
inline void add(int l,int r,const Type &v){
Type lres=0,rres=0;
int lm=0,rm=0,now=1;
for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1,now<<=1){
lres+=lm*tr[l].tag;
rres+=rm*tr[r].tag;
tr[l].vv+=v*(v*lm+2*lres);
tr[r].vv+=v*(v*rm+2*rres);
tr[l].v+=v*lm;
tr[r].v+=v*rm;
if(~l&1)lres+=tr[l^1].v,tr[l^1].tag+=v,tr[l^1].vv+=v*(v*now+2*tr[l^1].v),tr[l^1].v+=v*now,lm+=now;
if(r&1)rres+=tr[r^1].v,tr[r^1].tag+=v,tr[r^1].vv+=v*(v*now+2*tr[r^1].v),tr[r^1].v+=v*now,rm+=now;
}
lres+=lm*tr[l].tag;
rres+=rm*tr[r].tag;
tr[l].vv+=v*(v*lm+2*lres);
tr[r].vv+=v*(v*rm+2*rres);
tr[l].v+=v*lm;
tr[r].v+=v*rm;
lm+=rm;
lres+=rres;
l>>=1;
for(;l;l>>=1){
lres+=tr[l].tag*lm;
tr[l].v+=v*lm;
tr[l].vv+=v*(v*lm+2*lres);
}
}
inline Type query(int l,int r){
Type res = 0;
int lm=0,rm=0,now=1;
for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1,now<<=1){
res+=tr[l].tag*lm+tr[r].tag*rm;
if(~l&1)res+=tr[l^1].v,lm+=now;
if(r&1)res+=tr[r^1].v,rm+=now;
}
res+=tr[l].tag*lm+tr[r].tag*rm;
l>>=1;
lm+=rm;
for(;l;l>>=1){
res+=tr[l].tag*lm;
}
return res;
}
inline Type queryt(int l,int r){
Type lres=0,rres=0,res=0;
int lm = 0,rm = 0,now = 1;
for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1,now<<=1){
res+=tr[l].tag*tr[l].tag*lm+tr[r].tag*tr[r].tag*rm+2*(tr[l].tag*lres+tr[r].tag*rres);
lres+=tr[l].tag*lm;
rres+=tr[r].tag*rm;
if(~l&1)lres+=tr[l^1].v,res+=tr[l^1].vv,lm+=now;
if(r&1)rres+=tr[r^1].v,res+=tr[r^1].vv,rm+=now;
}
res+=tr[l].tag*tr[l].tag*lm+tr[r].tag*tr[r].tag*rm+2*(tr[l].tag*lres+tr[r].tag*rres);
l>>=1;
lm+=rm;
lres+=rres+tr[l].tag*lm+tr[r].tag*rm;
for(;l;l>>=1){
res+=tr[l].tag*(lm+2*lres);
lres+=tr[l].tag*lm;
}
return res;
}
inline void printd(double ans){//浮点数输出优化!
if(ans<0)ans=-ans,putchar('-');
ans+=0.00005;
print((int)ans);
putchar('.');
int res = (ans-(int)ans)*10000;
if(res==0){
puts("0000");
return;
}else if(res<10){
putchar('0');putchar('0');putchar('0');
}else if(res<100){
putchar('0');putchar('0');
}else if(res<1000){
putchar('0');
}
println(res);
}
int main(){
int n,q;
read(n);
read(q);
build(n);
int op,x,y;
Type v;
while(q--){
read(op);
read(x);
read(y);
switch(op){
case 1:
scanf("%lf",&v);
add(x,y,v);
break;
case 2:
printd(query(x,y)/(y-x+1));
break;
default:
double eva = query(x,y);
eva*=eva/(y-x+1);
printd((queryt(x,y)-eva)/(y-x+1));
break;
}
}
return 0;
}