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将期望花费多少费用呢?
自从上次在树上搞了这个操作之后
我觉得不是特别难了
我们思考暴力这个期望:
E
=
∑
i
=
l
r
∑
j
=
l
+
1
r
D
i
s
(
i
,
j
)
C
r
−
l
+
1
2
E=\frac{\sum_{i=l}^{r}\sum_{j=l+1}^{r}Dis(i,j)}{C_{r-l+1}^{2}}
E=Cr−l+12∑i=lr∑j=l+1rDis(i,j)
我们拆开这个式子
发现贡献是:
∑
i
=
l
r
W
i
(
r
−
i
+
1
)
(
l
−
i
+
1
)
\sum_{i=l}^{r}W_{i}(r-i+1)(l-i+1)
∑i=lrWi(r−i+1)(l−i+1)
暴力拆开:
(
r
−
l
+
1
−
r
∗
l
)
∗
W
i
+
(
r
+
l
)
∗
W
i
∗
i
−
W
i
∗
i
∗
i
(r-l+1-r*l)*W_{i}+(r+l)*W_{i}*i-W_{i}*i*i
(r−l+1−r∗l)∗Wi+(r+l)∗Wi∗i−Wi∗i∗i
实际上就是维护个区间求和
线段树维护就好了
那么区间加就可以维护了:
维护:
∑
i
\sum i
∑i和
∑
i
2
\sum i^{2}
∑i2
完。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define int long long
#define lc (p<<1)
#define rc (p<<1|1)
const int N=1e5+1000;
inline void read(int &x){
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
int a[N];
int GetGCD(int x,int y){
while(y){
int tmp=y;
y=x%y;
x=tmp;
}
return x;
}
struct Node{
int lson,rson;
int sum1;//a[i]
int sum2;//a[i]*i
int sum3;//a[i]*i*i
int sum4;//i
int sum5;//i*i
int lazy;
Node(){
lson=rson=sum1=sum2=sum3=sum4=sum5=lazy=0;
}
}T[N<<2];
Node operator + (Node A,Node B){
Node C;
C.sum1=A.sum1+B.sum1;
C.sum2=A.sum2+B.sum2;
C.sum3=A.sum3+B.sum3;
C.sum4=A.sum4+B.sum4;
C.sum5=A.sum5+B.sum5;
C.lson=A.lson;
C.rson=B.rson;
return C;
}
struct Segment_Tree{
inline void PushNow(int p,int val){
T[p].sum1+=(T[p].rson-T[p].lson+1)*val;
T[p].sum2+=T[p].sum4*val;
T[p].sum3+=T[p].sum5*val;
T[p].lazy+=val;
}
inline void PushDown(int p){
if(T[p].lazy){
PushNow(lc,T[p].lazy);
PushNow(rc,T[p].lazy);
T[p].lazy=0;
}
}
inline void Build(int p,int l,int r){
T[p].lson=l;
T[p].rson=r;
if(l==r){
T[p].sum1=a[l];
T[p].sum2=a[l]*l;
T[p].sum3=a[l]*l*l;
T[p].sum4=l;
T[p].sum5=l*l;
return;
}
int mid=(l+r)>>1;
Build(lc,l,mid);
Build(rc,mid+1,r);
T[p]=T[lc]+T[rc];
}
inline void Update(int p,int l,int r,int val){
if(l<=T[p].lson&&T[p].rson<=r){
PushNow(p,val);
return;
}
int mid=(T[p].lson+T[p].rson)>>1;
PushDown(p);
if(l<=mid)Update(lc,l,r,val);
if(mid< r)Update(rc,l,r,val);
T[p]=T[lc]+T[rc];
}
Node Query(int p,int l,int r){
if(l<=T[p].lson&&T[p].rson<=r){
return T[p];
}
int mid=(T[p].lson+T[p].rson)>>1;
PushDown(p);
Node ret;
if(l<=mid)ret=ret+Query(lc,l,r);
if(mid <r)ret=ret+Query(rc,l,r);
return ret;
}
}Tree;
int n,Q;
char S[10];
signed main(){
// freopen("test.in","r",stdin);
read(n);
read(Q);
Tree.Build(1,1,n);
while(Q--){
scanf("%s",S+1);
if(S[1]=='C'){
int l,r,v;
read(l);
read(r);
r--;
read(v);
Tree.Update(1,l,r,v);
}
else{
int l,r;
read(l);
read(r);
r--;
Node Now=Tree.Query(1,l,r);
int son=(r-l+1-r*l)*Now.sum1+(r+l)*Now.sum2-Now.sum3;
// cout<<Now.sum1<<" "<<Now.sum2<<" "<<Now.sum3<<'\n';
int mother=(r-l+2)*(r-l+1)/2;
int GCD=GetGCD(son,mother);
cout<<son/GCD<<"/"<<mother/GCD<<'\n';
}
}
}