Description
Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站。
Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。
政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。
无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l < r),在第l个到第r个收费站里等概率随机取出两个不同的收费站a和b,那么从a行驶到b将期望花费多少费用呢?
所有C操作中的v的绝对值不超过10000
在任何时刻任意道路的费用均为不超过10000的非负整数
100% n=100000 m=100000
Solution
期望实际上就是
∑ri=l(i−l+1)(r−i+1)v[i](2r−l+1)
∑
i
=
l
r
(
i
−
l
+
1
)
(
r
−
i
+
1
)
v
[
i
]
(
2
r
−
l
+
1
)
,拆开算贡献已经是常规操作
大概是这样的一个东西,根据求和里面与i的关系拆开来有三项
上线段树分别维护
∑v[i]
∑
v
[
i
]
,
∑v[i]∗i
∑
v
[
i
]
∗
i
和
∑v[i]∗i2
∑
v
[
i
]
∗
i
2
即可
Code
#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int N=400000;
struct data {
LL s1,s2,s3;
data operator +(data b) const {
return (data) {s1+b.s1,s2+b.s2,s3+b.s3};
}
} ;
LL s1[N*4],s2[N*4],s3[N*4];
LL tag[N*4];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
LL calc1(LL l,LL r) {
return ((r+1)*r-(l-1)*l)/2;
}
LL calc2(LL l,LL r) {
return r*(r+1)*(2*r+1)/6-(l-1)*l*(2*l-1)/6;
}
void push_down(int now,int l,int mid,int r) {
if (!tag[now]) return ;
LL w=tag[now]; tag[now]=0;
tag[now<<1]+=w; tag[now<<1|1]+=w;
s1[now<<1]+=(mid-l+1)*w;
s1[now<<1|1]+=(r-mid)*w;
s2[now<<1]+=calc1(l,mid)*w;
s2[now<<1|1]+=calc1(mid+1,r)*w;
s3[now<<1]+=(LL)w*calc2(l,mid);
s3[now<<1|1]+=(LL)w*calc2(mid+1,r);
}
void modify(int now,int tl,int tr,int l,int r,LL v) {
if (tl==l&&tr==r) {
tag[now]+=v;
s1[now]+=v*(r-l+1);
s2[now]+=v*calc1(l,r);
s3[now]+=v*calc2(l,r);
return ;
}
int mid=(tl+tr)>>1;
push_down(now,tl,mid,tr);
if (r<=mid) modify(now<<1,tl,mid,l,r,v);
else if (l>mid) modify(now<<1|1,mid+1,tr,l,r,v);
else {
modify(now<<1,tl,mid,l,mid,v);
modify(now<<1|1,mid+1,tr,mid+1,r,v);
}
s1[now]=s1[now<<1]+s1[now<<1|1];
s2[now]=s2[now<<1]+s2[now<<1|1];
s3[now]=s3[now<<1]+s3[now<<1|1];
}
data query(int now,int tl,int tr,int l,int r) {
if (tl==l&&tr==r) return (data) {s1[now],s2[now],s3[now]};
int mid=(tl+tr)>>1;
push_down(now,tl,mid,tr);
if (r<=mid) return query(now<<1,tl,mid,l,r);
if (l>mid) return query(now<<1|1,mid+1,tr,l,r);
data qx=query(now<<1,tl,mid,l,mid);
data qy=query(now<<1|1,mid+1,tr,mid+1,r);
return qx+qy;
}
LL gcd(LL x,LL y) {
return !y?x:gcd(y,x%y);
}
int main(void) {
int n=read();
for (int T=read();T--;) {
char opt[2]; scanf("%s",opt);
if (opt[0]=='C') {
int l=read(),r=read()-1,v=read();
modify(1,1,n-1,l,r,v);
} else if (opt[0]=='Q') {
int l=read(),r=read()-1;
data ret=query(1,1,n-1,l,r);
LL ans1=ret.s1*(LL)(r-l-(LL)r*l+1)+ret.s2*(LL)(r+l)-ret.s3;
LL ans2=(LL)(r-l+2)*(LL)(r-l+1)/2;
LL GCD=gcd(ans1,ans2);
printf("%lld/%lld\n", ans1/GCD,ans2/GCD);
}
}
return 0;
}