题意:很多段路,每一段有路费。给定一个区间,求区间内任意两点之间的花费总和的平均值。
比如 establish 2 4 就是求 (2到3的路费+3到4的路费+2到4的路费)/3 。
如果只维护区间的路费和,会超时,每次询问都要计算很多次。
假设要求的区间是 L到R ,假设某线段以K为左端点(L<=K<R),则这条线段计算次数为 ( K-L+1 )*(R-K)=-K*K+(L+R-1)*K +R(1-L)
设这条线段花费为S这条线段在本次内对总和的贡献为 -S*K*K +(L+R-1)*S*K +R(1-L)*S
对于所有线段,令K从L变化到R-1 只需要维护每个区间的 S*K*K , S*K , S的和,然后乘上系数。
#define FOR(i,n) for(long long (i)=1;(i)<=(n);(i)++)
#define For(i,n) for(long long (i)=0;(i)<(n);(i)++)
#define maxn 100005
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define cnt l,r,rt
#define LL long long
using namespace std;
LL sum[maxn<<2];
LL sumk[maxn<<2];
LL sumkk[maxn<<2];
LL add[maxn<<2];
LL multi[maxn<<2][3];
void PushUp(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
sumk[rt]=sumk[rt<<1]+sumk[rt<<1|1];
sumkk[rt]=sumkk[rt<<1]+sumkk[rt<<1|1];
}
void maintain(int rt,LL Add){
sum[rt]+=Add*multi[rt][0];
sumk[rt]+=Add*multi[rt][1];
sumkk[rt]+=Add*multi[rt][2];
}
void PushDown(int rt){
if(add[rt]){
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
maintain(rt<<1,add[rt]);
maintain(rt<<1|1,add[rt]);
add[rt]=0LL;
}
}
void build(int l,int r,int rt){
if(l==r){
sum[rt]=0LL;
sumk[rt]=0LL;
sumkk[rt]=0LL;
add[rt]=0LL;
multi[rt][0]=1;
multi[rt][1]=(LL)r;
multi[rt][2]=(LL)r*r;
return;
}
int m=(l+r)>>1;
build(ls);
build(rs);
PushUp(rt);
For(i,3){
multi[rt][i]=multi[rt<<1][i]+multi[rt<<1|1][i];
}
}
void update(int L,int R,LL C,int l,int r,int rt){
if(L <= l && r <= R){
add[rt]+=C;
maintain(rt,C);
return;
}
PushDown(rt);
int m=(l+r)>>1;
if(L <=m) update(L,R,C,ls);
if(R > m) update(L,R,C,rs);
PushUp(rt);
}
LL S,SK,SKK;
void query(int L,int R,int l,int r,int rt){
if(L <= l && r <= R){
S+=sum[rt];
SK+=sumk[rt];
SKK+=sumkk[rt];
return;
}
PushDown(rt);
int m=(l+r)>>1;
if(L <=m) query(L,R,ls);
if(R > m) query(L,R,rs);
}
int N,M;
int main(void)
{
while(cin>>N>>M){
build(1,N,1);
FOR(q,M){
char s[50];scanf("%s",s);
if(s[0]=='c'){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
update(a,b-1,(LL)c,1,N,1);
}
else{
int a,b;
scanf("%d%d",&a,&b);
S=0LL;SK=0LL;SKK=0LL;
query(a,b-1,1,N,1);
double ANS=-SKK+((LL)a+b-1)*SK+(LL)b*(1-a)*S;
LL D=(LL) (b-a)*(b-a+1)/2LL;
ANS/=D;
printf("%.10f\n",ANS);
}
}
}
return 0;
}