[HAOI2012]高速公路 [线段树 期望]
[HAOI2012]高速公路
Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。
政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。
无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l<r),在第l个到第r个收费站里等概率随机取出两个不同的收费站a和b,那么从a行驶到b将期望花费多少费用呢?
一条链 每次询问区间\([l,r]\)中期望花费
区间\([l,r]\)的期望花费 即一个平均值\(\begin{align*}\frac{\sum_{i=l}^r\sum_{j=i}^rdis[i][j]}{{r-l+1\choose 2}}\end{align*}\) (因为\(dis[i][j],(i>j)\)的情况和\((i<j)\)的情况是一样的 求平均值 就不用再多算一遍了
考虑第\(i\)条边的贡献 它总共在\((i-l+1)(r-i+1)\)个区间内 所以化简为\(\sum_iw[i](i-l+1)(r-i+1)\)
我将\(w[i]\)表示\(i-1\to i\)的道路花费 所以第\(i\)条边在区间\([l,r]\)内贡献了 \(w[i]*(i-l+1)(r-i)=w[i]* i *(l+r-1)-w[i]*i^2+r*(1-l)\)
即线段树\(\sum w[i]*i,\sum w[i]*i^2,\sum w[i]\)
然后注意一些小细节就好 对,注意\(l*l\)要爆int QAQ
struct node{ll sum1,sum2,sum3,add,pre1,pre2;}t[N<<2];
void pup(int o){
t[o].sum1=t[ls].sum1+t[rs].sum1,t[o].sum2=t[ls].sum2+t[rs].sum2,t[o].sum3=t[ls].sum3+t[rs].sum3;
}
void updnode(int o,int l,int r,ll k){
t[o].sum1+=k*t[o].pre1,t[o].sum2+=k*t[o].pre2,t[o].sum3+=((ll)r-l+1)*k,t[o].add+=k;
}
void pudw(int o,int l,int r){
if(!t[o].add) return;
int mid=l+r>>1;
updnode(ls,l,mid,t[o].add),updnode(rs,mid+1,r,t[o].add),t[o].add=0;
}
void upd(int o,int l,int r,int x,int y,ll k){
if(x>r||y<l) return;
if(x<=l&&r<=y){updnode(o,l,r,k);return;}
pudw(o,l,r);
int mid=l+r>>1;
upd(ls,l,mid,x,y,k),upd(rs,mid+1,r,x,y,k);
pup(o);
}
ll d,ans1,ans2,sum1,sum2,sum3;
void query(int o,int l,int r,int x,int y){
if(x>r||y<l) return;
if(x<=l&&r<=y){sum1+=t[o].sum1,sum2+=t[o].sum2,sum3+=t[o].sum3;return;}
pudw(o,l,r);
int mid=l+r>>1;
query(ls,l,mid,x,y),query(rs,mid+1,r,x,y);
pup(o);
}
void build(int o,int l,int r){
if(l==r){t[o]=(node){0,0,0,0,l,(ll)l*l};return;}
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
t[o].pre1=t[ls].pre1+t[rs].pre1,t[o].pre2=t[ls].pre2+t[rs].pre2;
}
ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
rd(n),rd(m);
char opt[5];
build(1,1,n);
for(int i=1,x,y,k;i<=m;++i){
scanf("%s",opt);rd(x),rd(y),--y;
if(opt[0]=='C'){
rd(k);
upd(1,1,n,x,y,(ll)k);
}
else{
sum1=sum2=sum3=0ll;query(1,1,n,x,y);++y;
ans1=sum1*((ll)y+x-1)-sum2+(ll)y*(1-x)*sum3,ans2=((ll)y-x)*((ll)y-x+1)/2;
d=gcd(ans1,ans2),ans1/=d,ans2/=d;
if(!ans1) puts("0/1");
else printf("%lld/%lld\n",ans1,ans2);
}
}
return 0;
}