这个期望显然可以表示成总价值/总方案数.
然后我们用线段树依次维护 $sum val[i]$,$sum val[i] imes i$,$sum val[i] imes i^2$ 即可.
code:
#include <cmath> #include <cstdio> #include <string> #include <algorithm> #define N 100006 #define ll long long #define lson now<<1 #define rson now<<1|1 using namespace std; namespace IO { void setIO(string s) { string in=s+".in"; string out=s+".out"; freopen(in.c_str(),"r",stdin); // freopen(out.c_str(),"w",stdout); } }; ll re2,re3,re4; int n,m; struct node { int l,r; ll sum[5],tag; }s[N<<2]; void pushup(int now) { for(int i=0;i<5;++i) s[now].sum[i]=s[lson].sum[i]+s[rson].sum[i]; } void build(int l,int r,int now) { s[now].l=l; s[now].r=r; if(l==r) { s[now].sum[0]=l; s[now].sum[1]=(ll)l*l; return; } int mid=(l+r)>>1; build(l,mid,lson),build(mid+1,r,rson),pushup(now); } void mark(int now,ll d) { s[now].sum[2]+=d*s[now].sum[0]; s[now].sum[3]+=(s[now].r-s[now].l+1)*d; s[now].sum[4]+=d*s[now].sum[1]; s[now].tag+=d; } void pushdown(int now) { if(s[now].tag) mark(lson,s[now].tag),mark(rson,s[now].tag),s[now].tag=0; } void update(int l,int r,int now,int L,int R,int v) { if(l>=L&&r<=R) { mark(now,v); return; } int mid=(l+r)>>1; pushdown(now); if(L<=mid) update(l,mid,lson,L,R,v); if(R>mid) update(mid+1,r,rson,L,R,v); pushup(now); } void query(int l,int r,int now,int L,int R) { if(l>=L&&r<=R) { re2+=s[now].sum[2]; re3+=s[now].sum[3]; re4+=s[now].sum[4]; return; } int mid=(l+r)>>1; pushdown(now); if(L<=mid) query(l,mid,lson,L,R); if(R>mid) query(mid+1,r,rson,L,R); } int main() { // IO::setIO("input"); int i,j; scanf("%d%d",&n,&m),--n; build(1,n,1); for(i=1;i<=m;++i) { char op[3]; scanf("%s",op); if(op[0]=='C') { int l,r,v; scanf("%d%d%d",&l,&r,&v); --r; update(1,n,1,l,r,v); } else { int l,r; scanf("%d%d",&l,&r); --r; re2=re3=re4=0; query(1,n,1,l,r); ll up=(r+l)*re2+(ll)(r-(ll)r*l-l+1)*re3-re4; ll dw=(ll)(r-l+2)*(r-l+1)/2; ll g=__gcd(up,dw); up/=g,dw/=g; printf("%lld/%lld ",up,dw); } } return 0; }