题解 P2221 【[HAOI2012]高速公路】
这个题目真的是一个很好的练习自己概率期望的题!
看到什么区间加法,一秒线段树
然后如何维护边之间的和呢?
比如说
1号花费2到2号,2号花费4到3号
把每一条路的花费作为终点处的点的权值就好了
此时每一个点的权值就是
这样就可以了。求
用线段树做加法也同理
我们记录一个前缀和数组 sum,然后发现 超舒服
根据期望的定义其实就是平均数
答案就是
然后呢?下面谁都会求啊,我们考虑上面
用线段树维护这个奇怪的东西
我们根据之前做过的题目,考虑一个套路:
枚举
比如说区间
同理,
也被包含
也被包含
所以我们可以得知第
所以上面的答案转化成了
还是不能维护啊
那就拆开吧!
分离
就
然后就好像可以用线段树维护了
维护
维护
维护
上面的答案就是
但是有区间加法,怎么维护这些的和呢?
设某线段树节点控制的区域为
有
即
每一个线段树节点额外记录一个
即
每一个线段树节点再额外记录一个
于是这题就做完啦!
最后注意要约分啊!
很容易爆 long long 所以建议多开一些 long long。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();};
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-48;ch=getchar();};
return x*f;
}
int n,m;
struct node{
ll sum1,sum2,sum3,sum4,sum5,lazy;//如上文所述
}g[1000001];
inline void pushup(int rt){
g[rt].sum1=g[rt<<1].sum1+g[rt<<1|1].sum1;
g[rt].sum2=g[rt<<1].sum2+g[rt<<1|1].sum2;
g[rt].sum3=g[rt<<1].sum3+g[rt<<1|1].sum3;
}
void build(int rt,int lb,int rb){
if (lb==rb){g[rt].sum4=1LL*lb;g[rt].sum5=1LL*lb*lb;return;}//预处理sum4,sum5
int mid=lb+rb>>1;
build(rt<<1,lb,mid);build(rt<<1|1,mid+1,rb);
g[rt].sum4=g[rt<<1].sum4+g[rt<<1|1].sum4;
g[rt].sum5=g[rt<<1].sum5+g[rt<<1|1].sum5;
}
inline void pushdown(int rt,int lb,int rb){
if (g[rt].lazy){
int mid=lb+rb>>1,ls=rt<<1,w=g[rt].lazy,rs=rt<<1|1;
g[ls].lazy+=1LL*w;g[rs].lazy+=1LL*w;
g[ls].sum1+=1LL*(mid-lb+1)*w;g[rs].sum1+=1LL*(rb-mid)*w;
g[ls].sum2+=1LL*w*g[ls].sum4;g[rs].sum2+=1LL*w*g[rs].sum4;
g[ls].sum3+=1LL*w*g[ls].sum5;g[rs].sum3+=1LL*w*g[rs].sum5;
g[rt].lazy=0;
}
}
void update(int rt,int lb,int rb,int l,int r,ll w){
if (lb>r||rb<l) return;
if (lb>=l&&rb<=r){
g[rt].sum1+=1LL*(rb-lb+1)*w;g[rt].sum2+=1LL*w*g[rt].sum4;
g[rt].sum3+=1LL*w*g[rt].sum5;g[rt].lazy+=1LL*w;return;
}
pushdown(rt,lb,rb);
int mid=lb+rb>>1;
update(rt<<1,lb,mid,l,r,w);update(rt<<1|1,mid+1,rb,l,r,w);
pushup(rt);
}
void query(int rt,int lb,int rb,int l,int r,ll &sum1,ll &sum2,ll &sum3){//由于想减少代码量以及常数于是就尝试用void记录答案
if (lb>r||rb<l) return;
if (lb>=l&&rb<=r){sum1+=g[rt].sum1;sum2+=g[rt].sum2;sum3+=g[rt].sum3;return;}
pushdown(rt,lb,rb);
int mid=lb+rb>>1;
query(rt<<1,lb,mid,l,r,sum1,sum2,sum3);query(rt<<1|1,mid+1,rb,l,r,sum1,sum2,sum3);
}
int main(){
n=read(),m=read();
build(1,1,n);
while (m--){
char s[12];ll l,r;scanf("%s",s);l=read(),r=read();
if (s[0]=='C'){
ll w=read();
if (l==r) continue;
update(1,1,n,l+1,r,w);
}else{
ll S1=0,S2=0,S3=0;
query(1,1,n,l+1,r,S1,S2,S3);
ll Up=-S3+(l+r+1)*S2+(r-(l+1)-(l+1)*r+1)*S1,Down=(r-l+1)*(r-l)/2;//Up是分子,Down是分母
ll Gcd=__gcd(Up,Down);
printf("%lld/%lld\n",Up/Gcd,Down/Gcd);//约分
}
}
}