暂无链接
小 G 的线段树
【题目描述】
小 G 是一名OIerOIerOIer,他最近学习了一种高级数据结构——线段树,
做题时,他遇到了如下的问题:
维护一个序列,要求支持三种操作:
1.区间加上一个数xxx
2.区间赋值为一个数xxx
3.求一个区间的和
小 G 是一个爱思考的同学。他在做出来了这题之后,又提出了一个新的问题:如果把所有的操作随机打乱,那么每个询问的期望输出是多少呢?注意,随机打乱既所有m!m!m!种操作排列的出现概率均等。为了方便,我们假设询问在最后且不参与随机打乱。
考虑到精度问题,只要你的答案和标程答案的相对误差不超过1e−81e-81e−8就算正确。
【输入格式】
第一行三个整数n m qn\ m\ qn m q,分别表示序列长度、修改数和询问数接下来一行nnn个整数aia_iai,表示序列的初始值接下来mmm行,每行444个整数c,l,r,xc,l,r,xc,l,r,x
若c=1c=1c=1,则表示把区间[l,r][l,r][l,r]的元素加上xxx
若c=2c=2c=2,则表示把区间[l,r][l,r][l,r]的元素全赋为xxx
接下来qqq行,每行222个整数l,rl,rl,r,代表每次询问的左右端点。
【输出格式】
qqq行,每行一个实数,按照输入顺序分别为qqq个询问的期望答案
答案保留 3 位小数
【样例 1】
segment. in
5 4 8
2 3 3 3 3
1 1 3 2
1 3 5 1
2 2 4 1
2 1 3 4
1 1
2 2
3 3
4 4
5 5
1 3
2 5
1 5
segment.out
5.000
3.167
3.500
1.500
4.000
11.667
12.167
17.167
【样例 2】
见选手目录下 segment. in/segment.ans
【数据范围与约定】
对于30%30\%30%的数据,n<=10,m<=10n<=10,m<=10n<=10,m<=10
对于60%60\%60%的数据,n<=1000,m<=1000n<=1000,m<=1000n<=1000,m<=1000
对于另外10%10\%10%的数据,没有操作111
对于另外10%10\%10%的数据,q=1q=1q=1
对于100%100\%100%的数据,n,m,q<=100000,1<=ai<=100000n,m,q<=100000,1<=a_i<=100000n,m,q<=100000,1<=ai<=100000,111操作中的
x<=100x<=100x<=100,222操作中的x<=100000x<=100000x<=100000。
【提示】
离散型随机变量的一切可能取值xix_ixi与其对应的概率pip_ipi的乘积之和称为该离散型随机变量的期望,即E(x)=∑i=1nxipiE(x)=\sum_{i=1}^nx_ip_iE(x)=∑i=1nxipi 。
题解
先考虑如何计算单点的答案:
首先,该点的初始值只在无赋值操作的时候有效;考虑nnn个赋值操作将整个操作序列分成了n+1n+1n+1份,只有最后一个赋值操作有效,所以赋值操作对答案的贡献为xn\frac{x}{n}nx;只有在最后一个赋值操作之后的加操作有效,所以加操作对答案的贡献为xn+1\frac{x}{n+1}n+1x。
我们只需要查分统计每个点的赋值操作个数、赋值与加操作权值即可。
代码
#include<cstdio>
const int M=1e5+5;
int tot1,tot2,n,m,q,que[M];
long long add[M],ass[M],cot[M];
double ans[M];
void in(){scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;++i)scanf("%d",&que[i]);}
void ac()
{
for(int i=1,op,l,r,x;i<=m;++i)
{
scanf("%d%d%d%d",&op,&l,&r,&x);
op==1?(add[l]+=x,add[r+1]-=x):(ass[l]+=x,ass[r+1]-=x,++cot[l],--cot[r+1]);
}
for(int i=1;i<=n;++i)add[i]+=add[i-1],ass[i]+=ass[i-1],cot[i]+=cot[i-1],ans[i]=add[i]/(cot[i]+1.0);
for(int i=1;i<=n;++i)ans[i]+=(cot[i]?1.0*ass[i]/cot[i]:que[i]);
for(int i=1;i<=n;++i)ans[i]+=ans[i-1];
for(int i=1,l,r;i<=q;++i)
scanf("%d%d",&l,&r),printf("%.3lf\n",ans[r]-ans[l-1]);
}
int main(){in(),ac();}