由于本题中的询问是等概率选取两个收费站,因此期望花费就等于所有可能花费之和除以可能性数,即:
其中s[i][j]是第 i i 到个区间的长度之和,注意原题问的是第l个收费站到第r个收费站区间内的期望花费,相当于询问左闭右开区间。
明显这类区间修改和区间询问的问题可以使用线段树,让我们试试用线段树来维护上式右侧的分子。
然而……怎么合并啊……
让我们试着推一下,设 sum(l,r)=∑l≤i≤j≤r−1s(i,j) s u m ( l , r ) = ∑ l ≤ i ≤ j ≤ r − 1 s ( i , j ) 表示 l l 到的所有区间和之和。
这时候,我们可以把区间
[l,r]
[
l
,
r
]
拆成
[l,mid]
[
l
,
m
i
d
]
和
[mid+1,r]
[
m
i
d
+
1
,
r
]
,则
sum[l][r]
s
u
m
[
l
]
[
r
]
明显就等于
sum(l,mid)+sum(mid+1,r)
s
u
m
(
l
,
m
i
d
)
+
s
u
m
(
m
i
d
+
1
,
r
)
再加上所有跨mid的区间和之和,
即:
其中前后两个求和 rs(l,r)=∑ri=ls[i][r] r s ( l , r ) = ∑ i = l r s [ i ] [ r ] 以及 ls(l,r)=∑ri=ls[l][i] l s ( l , r ) = ∑ i = l r s [ l ] [ i ] 都可以用线段树维护:
于是维护区间的 sum,ls,rs,s s u m , l s , r s , s 值就可以了,说起来很简单实际上很难……反正我调了整整五个小时
#include <bits/stdc++.h>
using namespace std;
char buf[3000000],*pp=buf;
#define LL long long
//#define getchar() *(pp++)
inline int read()
{
register int x=0,w=1;register char ch=getchar();
while(ch<'0'||ch>'9')w=(ch=='-'?-1:1),ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
int n,m,s[400010],lazy[400010];
LL sl[400010],sr[400010],ss[400010],ssq[100010];
inline void push_down(int k,int l,int r)
{
int tmp=lazy[k];
if(tmp&&l!=r)
{
int mid=(l+r)>>1;
s[k<<1]+=(mid-l+1)*tmp;
s[k<<1|1]+=(r-mid)*tmp;
sl[k<<1]+=1LL*(mid-l+1)*(mid-l+2)/2*tmp;
sl[k<<1|1]+=1LL*(r-mid)*(r-mid+1)/2*tmp;
sr[k<<1]+=1LL*(mid-l+1)*(mid-l+2)/2*tmp;
sr[k<<1|1]+=1LL*(r-mid)*(r-mid+1)/2*tmp;
ss[k<<1]+=ssq[mid-l+1]*tmp;
ss[k<<1|1]+=ssq[r-mid]*tmp;
lazy[k<<1]+=tmp;
lazy[k<<1|1]+=tmp;
}
lazy[k]=0;
}
inline void update(int k,int l,int r)
{
int mid=(l+r)>>1;
s[k]=s[k<<1]+s[k<<1|1];
sl[k]=sl[k<<1]+sl[k<<1|1]+1LL*s[k<<1]*(r-mid);
sr[k]=sr[k<<1]+sr[k<<1|1]+1LL*s[k<<1|1]*(mid-l+1);
ss[k]=ss[k<<1]+ss[k<<1|1]+sr[k<<1]*(r-mid)+sl[k<<1|1]*(mid-l+1);
}
void change(int k,int l,int r,int L,int R,int x)
{
push_down(k,l,r);
if(L<=l&&r<=R)
{
lazy[k]+=x;
s[k]+=(r-l+1)*x;
sl[k]+=1LL*(r-l+1)*(r-l+2)/2*x;
sr[k]+=1LL*(r-l+1)*(r-l+2)/2*x;
ss[k]+=ssq[r-l+1]*x;
return;
}
int mid=(l+r)>>1;
if(L<=mid)
{
change(k<<1,l,mid,L,R,x);
}
if(R>mid)
{
change(k<<1|1,mid+1,r,L,R,x);
}
update(k,l,r);
}
LL query(int k,int l,int r,int L,int R,LL &x1,LL &x2,LL &xs)//在左侧或右侧
{
push_down(k,l,r);
if(L<=l&&r<=R)
{
x1=sl[k];
x2=sr[k];
xs=s[k];
return ss[k];
}
LL ret=0,x11,x12,x21,x22,xs1,xs2;
int mid=(l+r)>>1;
if(R<=mid)
{
return query(k<<1,l,mid,L,R,x1,x2,xs);
}
else if(L>mid)
{
return query(k<<1|1,mid+1,r,L,R,x1,x2,xs);
}
else
{
ret+=query(k<<1,l,mid,L,mid,x11,x12,xs1);
ret+=query(k<<1|1,mid+1,r,mid+1,R,x21,x22,xs2);
x1=x11+x21+xs1*(R-mid);
x2=x12+x22+xs2*(mid-L+1);
xs=xs1+xs2;
return ret+x12*(R-mid)+x21*(mid-L+1);
}
}
int main()
{
// fread(buf,sizeof(char),sizeof(buf),stdin);
cin>>n>>m;
ssq[1]=1;
for(int i=2;i<=n;i++)
{
ssq[i]=ssq[i-2]+1LL*i*i;
}
for(int i=1;i<=m;i++)
{
register char ch=getchar();
while(ch!='C'&&ch!='Q')ch=getchar();
int l=read(),r=read();
LL x;
if(ch=='C')
{
x=(LL)read();
change(1,1,n-1,l,r-1,x);
}
else
{
LL ret=query(1,1,n-1,l,r-1,x,x,x),mul=1LL*(r-l)*(r-l+1)/2,ggcd=__gcd(ret,mul);
ret/=ggcd;
mul/=ggcd;
printf("%lld/%lld\n",ret,mul);
}
}
return 0;
}
/*
10 5
C 2 8 1
C 7 8 2
C 7 8 1
C 4 6 2
Q 2 7
*/