#include<cstring>
#include<iostream>
#include<algorithm>
#include<iomanip>
using namespace std;
#define N 100010
#define LL double
#define lc u<<1
#define rc u<<1|1
#define ll long long
LL w[N];
struct Tree
{
ll l,r;
LL sum,add;
}tr1[N*4],tr2[N*4];
void pushup(ll u){
tr1[u].sum=tr1[lc].sum+tr1[rc].sum;
tr2[u].sum=tr2[lc].sum+tr2[rc].sum;
}
void pushdown(ll u)
{
if(tr1[u].add)
{
tr1[lc].sum+=tr1[u].add*(tr1[lc].r-tr1[lc].l+1);
tr1[rc].sum+=tr1[u].add*(tr1[rc].r-tr1[rc].l+1);
tr1[lc].add+=tr1[u].add;
tr1[rc].add+=tr1[u].add;
tr1[u].add=0;
}
if(tr2[u].add)
{
tr2[lc].sum+=2*tr2[u].add*tr1[u].sum+(tr2[lc].r-tr2[lc].l+1)*tr2[u].add*tr2[u].add;
tr2[rc].sum+=2*tr2[u].add*tr1[u].sum+(tr2[rc].r-tr2[rc].l+1)*tr2[u].add*tr2[u].add;;
tr2[lc].add+=tr2[u].add;
tr2[rc].add+=tr2[u].add;
tr2[u].add=0;
}
}
void build1(ll u,ll l,ll r)
{
tr1[u]={l,r,w[l],0};
if(l==r) return;
ll m=l+r>>1;
build1(lc,l,m);
build1(rc,m+1,r);
pushup(u);
}
void build2(ll u,ll l,ll r)
{
tr2[u]={l,r,w[l]*w[l],0};
if(l==r) return;
ll m=l+r>>1;
build2(lc,l,m);
build2(rc,m+1,r);
pushup(u);
}
void change(ll u,ll l,ll r,LL k)
{
if(l>tr1[u].r || r<tr1[u].l) return;
if(l<=tr1[u].l&&tr1[u].r<=r)
{
tr1[u].sum+=(tr1[u].r-tr1[u].l+1)*k;
tr1[u].add+=k;
tr2[u].add+=k;
return;
}
ll m=tr1[u].l+tr1[u].r>>1;
pushdown(u);
if(l<=m) change(lc,l,r,k);
if(r>m) change(rc,l,r,k);
pushup(u);
}
LL query(Tree tree[],ll u,ll l,ll r){
if(l<=tree[u].l&&tree[u].r<=r) return tree[u].sum;
ll m=tree[u].l+tree[u].r>>1;
pushdown(u);
LL ans=0;
if(l<=m) ans+=query(tree,lc,l,r);
if(r>m) ans+=query(tree,rc,l,r);
return ans;
}
int main()
{
int n,m,op,x,y;
double k;
cin>>n>>m;
for(int i=1;i<=n;++i) cin>>w[i];
build1(1,1,n);
build2(1,1,n);
while(m--)
{
cin>>op>>x>>y;
if(op==2) cout<<fixed<<setprecision(4)<<query(tr1,1,x,y)/((y - x + 1) * 1.0)<<endl;
else if(op==1) cin>>k,change(1,x,y,k);
else cout<<fixed<<setprecision(4)<<query(tr2,1,x,y)/((y - x + 1) * 1.0)-query(tr1,1,x,y)/((y - x + 1) * 1.0)*(query(tr1,1,x,y))/((y - x + 1) * 1.0)<<endl;
}
return 0;
}