高速公路题解
我们看一看题,就知道概率是是区间内所有线段的权值和/线段个数。
那么,我们需要动态维护区间的数据结构,
很容易想到线段树,
考虑,如何将两个区间合并:
注:以下线段树上的每个点的\(sum\)在代码中为\(sum2\),仅为方便理解。
不妨设每个区间\([l,r]\)内的所有线段权值和为\(w\),\([l,r]\)的线段权值为\(sum\),左端点为\(l\)的所有线段权值和为\(lw\),右端点为\(r\)的所有线段的权值和为\(rw\),懒标记为\(lazy\),区间长度为\(lenx=r-l+1\)
假如此区间为\(x\),左区间为\(lc\),右区间为\(rc\):
\(x\)的\(w\)除去由\(lc,rc\)各自区间内部的\(w\)外,
还由经过左右两个区间的线段构成,
画图理解一下:
然后第二个问题来了,如何维护\(lw,rw\)?
至于\(sum,lazy\)还用说吗? 线段树模板啊!
xd pushup(xd u,xd v){
xd ans; int len=u.lenx+v.lenx;
ans.lw=u.lw+v.lw+v.lenx*u.sum2,ans.rw=u.rw+v.rw+u.lenx*v.sum2,ans.lazy=0;
ans.w=u.w+v.w+u.lenx*v.lw+v.lenx*u.rw,ans.sum2=u.sum2+v.sum2,ans.lenx=len;
return ans;
}
再想想下传标记:
对于每个\(x\)的\(w\),所有线段都加了线段长度\(*lazy[x]\);
设\(sum[len]\)为长度为\(len\)的区间所有线段的长度和。
由\(l-1\)每增加一个长度,则每个长度的线段都有一个,即为:\(\sum_{i=1}^{l}=/frac{(l+1)*l}{2}\)
递推即可。
for(ll i=1;i<=n;++i) sum[i]=sum[i-1]+i*(i+1)/2;
所以:
t[lc].w+=sum[t[lc].lenx]*t[x].lazy,t[rc].w+=sum[t[rc].lenx]*t[x].lazy;
对于\(lw\)和\(rw\):
区间\([l,r]\)长度在[1,r-l+1]的线段都有一种:
t[lc].lw+=(t[lc].lenx+1)*t[lc].lenx/2*t[x].lazy,t[lc].rw+=(t[lc].lenx+1)*t[lc].lenx/2*t[x].lazy;
t[rc].lw+=(t[rc].lenx+1)*t[rc].lenx/2*t[x].lazy,t[rc].rw+=(t[rc].lenx+1)*t[rc].lenx/2*t[x].lazy;
\(sum,lenx,lazy\)的下传也不讲了。
#include
#define ll long long
#define lc x<<1
#define rc x<<1|1
using namespace std;
const int N=1e5+6;
int n,m,t3;
ll sum[N],o,p,q,t1,t2;
char c[12];
struct xd{ll w,lazy,lw,rw,lenx,sum2;}t[N<<2];
inline int read(){
int T=0,F=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
return F*T;
}
ll gcd(ll u,ll v){return u%v==0?v:gcd(v,u%v);}
void pushdown(int x){
if(t[x].lazy){
t[lc].lazy+=t[x].lazy,t[rc].lazy+=t[x].lazy;
t[lc].w+=sum[t[lc].lenx]*t[x].lazy,t[rc].w+=sum[t[rc].lenx]*t[x].lazy;
t[lc].lw+=(t[lc].lenx+1)*t[lc].lenx/2*t[x].lazy,t[lc].rw+=(t[lc].lenx+1)*t[lc].lenx/2*t[x].lazy;
t[rc].lw+=(t[rc].lenx+1)*t[rc].lenx/2*t[x].lazy,t[rc].rw+=(t[rc].lenx+1)*t[rc].lenx/2*t[x].lazy;
t[lc].sum2+=t[lc].lenx*t[x].lazy,t[rc].sum2+=t[rc].lenx*t[x].lazy;
t[x].lazy=0;
}
}
xd pushup(xd u,xd v){
xd ans; int len=u.lenx+v.lenx;
ans.lw=u.lw+v.lw+v.lenx*u.sum2,ans.rw=u.rw+v.rw+u.lenx*v.sum2,ans.lazy=0;
ans.w=u.w+v.w+u.lenx*v.lw+v.lenx*u.rw,ans.sum2=u.sum2+v.sum2,ans.lenx=len;
return ans;
}
void build(int l,int r,int x){
t[x].lenx=r-l+1;
if(l==r) return;
int mid=l+r>>1;
build(l,mid,lc),build(mid+1,r,rc);
}
void update(ll l,ll r,int p,int q,int x,ll y){
if(p<=l&&r<=q){t[x].lazy+=y,t[x].w+=sum[r-l+1]*y,t[x].lw+=(r-l+1)*(r-l+2)/2*y,t[x].rw+=(r-l+1)*(r-l+2)/2*y,t[x].sum2+=(r-l+1)*y; return;}
pushdown(x); int mid=l+r>>1;
if(p<=mid) update(l,mid,p,q,lc,y);
if(q>mid) update(mid+1,r,p,q,rc,y);
t[x]=pushup(t[lc],t[rc]);
}
xd query(int l,int r,int p,int q,int x){
if(p<=l&&r<=q){return t[x];}
pushdown(x); int mid=l+r>>1; xd ans;
if(q<=mid) ans=query(l,mid,p,q,lc);
else if(p>mid) ans=query(mid+1,r,p,q,rc);
else ans=pushup(query(l,mid,p,q,lc),query(mid+1,r,p,q,rc));
return ans;
}
int main(){
n=read(),m=read(),--n;
for(ll i=1;i<=n;++i) sum[i]=sum[i-1]+i*(i+1)/2;
build(1,n,1);
for(int i=1;i<=m;++i){
scanf("%s",c); t1=read(),t2=read()-1;
if(c[0]=='C') t3=read(),update(1,n,t1,t2,1,t3);
else{
o=(t2-t1+1)*(t2-t1+2)/2,p=query(1,n,t1,t2,1).w;
if(p) q=gcd(o,p),o/=q,p/=q;
else o=1;
printf("%lld/%lld\n",p,o);
}
}
return 0;
}