Time Limit: 20 Sec
Memory Limit: 128 MB
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将期望花费多少费用呢?
Input
第一行2个正整数N,M,表示有N个收费站,M次调整或询问
接下来M行,每行将出现以下两种形式中的一种
C l r v 表示将第l个收费站到第r个收费站之间的所有道路的通行费全部增加v
Q l r 表示对于给定的l,r,要求回答小A的问题
所有C与Q操作中保证1<=l<r<=N
Output
对于每次询问操作回答一行,输出一个既约分数
若答案为整数a,输出a/1
HINT
所有C操作中的v的绝对值不超过10000
在任何时刻任意道路的费用均为不超过10000的非负整数
所有测试点的详细情况如下表所示
Test N M
1 =10 =10
2 =100 =100
3 =1000 =1000
4 =10000 =10000
5 =50000 =50000
6 =60000 =60000
7 =70000 =70000
8 =80000 =80000
9 =90000 =90000
10 =100000 =100000
题目分析
根据题意列表达式
a
n
s
=
∑
i
=
L
R
∑
j
=
L
R
d
i
s
(
i
,
j
)
C
R
−
L
+
1
2
ans=\frac{\sum_{i=L}^R\sum_{j=L}^Rdis(i,j)}{C_{R-L+1}^{2}}
ans=CR−L+12∑i=LR∑j=LRdis(i,j)
想办法维护上面那一坨,设
v
i
v_i
vi为第
i
i
i条边的权值,重新表达分子
∑
i
=
L
R
−
1
w
i
(
i
−
L
+
1
)
(
R
−
i
+
1
)
\sum_{i=L}^{R-1}w_i(i-L+1)(R-i+1)
i=L∑R−1wi(i−L+1)(R−i+1)
即对每条边计算有多少对点的路径经过它
展开后得
(
R
+
1
)
(
1
−
L
)
∑
w
i
+
(
L
+
R
)
∑
i
∗
w
i
−
∑
i
2
w
i
(R+1)(1-L)\sum w_i+(L+R)\sum i*w_i-\sum i^2w_i
(R+1)(1−L)∑wi+(L+R)∑i∗wi−∑i2wi
用线段树分别维护三个和式即可
∑
i
=
1
n
i
2
=
(
2
n
+
1
)
∗
n
∗
(
n
+
1
)
6
\sum_{i=1}^ni^2=\frac{(2n+1)*n*(n+1)}{6}
∑i=1ni2=6(2n+1)∗n∗(n+1)
注意边化点在后计算上的细节
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lt;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=100010;
int n,m;
lt sum[3][maxn<<2],add[maxn<<2];
char ss[5];
lt gcd(lt a,lt b){ return b==0?a:gcd(b,a%b);}
lt calc(lt x){ return 1ll*(x*2+1)*x*(x+1)/6;}
void pushup(int p)
{
int lc=p<<1,rc=p<<1|1;
for(int i=0;i<3;++i)
sum[i][p]=sum[i][p<<1]+sum[i][p<<1|1];
}
void modify(lt s,lt t,lt p,lt v)
{
sum[0][p]+=v*(t-s+1);
sum[1][p]+=v*(s+t)*(t-s+1)/2;
sum[2][p]+=v*(calc(t)-calc(s-1));
add[p]+=v;
}
void pushd(lt s,lt t,lt mid,int p)
{
if(!add[p]) return;
modify(s,mid,p<<1,add[p]);
modify(mid+1,t,p<<1|1,add[p]);
add[p]=0;
}
void update(int ll,int rr,lt s,lt t,int p,lt v)
{
if(ll<=s&&t<=rr){ modify(s,t,p,v); return;}
int mid=s+t>>1;
pushd(s,t,mid,p);
if(ll<=mid) update(ll,rr,s,mid,p<<1,v);
if(rr>mid) update(ll,rr,mid+1,t,p<<1|1,v);
pushup(p);
}
lt query(int ll,int rr,lt s,lt t,int p,int d)
{
if(ll<=s&&t<=rr) return sum[d][p];
int mid=s+t>>1; lt res=0;
pushd(s,t,mid,p);
if(ll<=mid) res+=query(ll,rr,s,mid,p<<1,d);
if(rr>mid) res+=query(ll,rr,mid+1,t,p<<1|1,d);
return res;
}
lt C(lt a,lt b)
{
lt res=1;
for(lt i=1;i<=b;++i)
res=res*(a-b+i)/i;
return res;
}
void solve(lt L,lt R)
{
lt res=0;
res+=(R+1)*(1ll-L)*query(L,R,1,n,1,0);
res+=(L+R)*query(L,R,1,n,1,1);
res-=query(L,R,1,n,1,2);
//lt c=C(R-L+2,2);
lt c=(R-L+2)*(R-L+1)/2;
lt g=gcd(res,c);
printf("%lld/%lld\n",res/g,c/g);
}
int main()
{
n=read();m=read();
while(m--)
{
scanf("%s",&ss);
int ll=read(),rr=read()-1;
if(ss[0]=='C') update(ll,rr,1,n,1,read());
else if(ss[0]=='Q') solve(ll,rr);
}
return 0;
}