[2018.10.18 T3] 小 G 的线段树

暂无链接

小 G 的线段树

【题目描述】

小 G 是一名 O I e r OIer OIer,他最近学习了一种高级数据结构——线段树,
做题时,他遇到了如下的问题:
维护一个序列,要求支持三种操作:
1.区间加上一个数 x x x
2.区间赋值为一个数 x x x
3.求一个区间的和
小 G 是一个爱思考的同学。他在做出来了这题之后,又提出了一个新的问题:如果把所有的操作随机打乱,那么每个询问的期望输出是多少呢?注意,随机打乱既所有 m ! m! m!种操作排列的出现概率均等。为了方便,我们假设询问在最后且不参与随机打乱。
考虑到精度问题,只要你的答案和标程答案的相对误差不超过 1 e − 8 1e-8 1e8就算正确。

【输入格式】

第一行三个整数 n   m   q n\ m\ q n m q,分别表示序列长度、修改数和询问数接下来一行 n n n个整数 a i a_i ai,表示序列的初始值接下来 m m m行,每行 4 4 4个整数 c , l , r , x c,l,r,x c,l,r,x
c = 1 c=1 c=1,则表示把区间 [ l , r ] [l,r] [l,r]的元素加上 x x x
c = 2 c=2 c=2,则表示把区间 [ l , r ] [l,r] [l,r]的元素全赋为 x x x
接下来 q q q行,每行 2 2 2个整数 l , r l,r l,r,代表每次询问的左右端点。

【输出格式】

q q q行,每行一个实数,按照输入顺序分别为 q q q个询问的期望答案
答案保留 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 &lt; = 10 , m &lt; = 10 n&lt;=10,m&lt;=10 n<=10,m<=10
对于 60 % 60\% 60%的数据, n &lt; = 1000 , m &lt; = 1000 n&lt;=1000,m&lt;=1000 n<=1000,m<=1000
对于另外 10 % 10\% 10%的数据,没有操作 1 1 1
对于另外 10 % 10\% 10%的数据, q = 1 q=1 q=1
对于 100 % 100\% 100%的数据, n , m , q &lt; = 100000 , 1 &lt; = a i &lt; = 100000 n,m,q&lt;=100000,1&lt;=a_i&lt;=100000 n,m,q<=1000001<=ai<=100000 1 1 1操作中的
x &lt; = 100 x&lt;=100 x<=100 2 2 2操作中的 x &lt; = 100000 x&lt;=100000 x<=100000

【提示】

离散型随机变量的一切可能取值 x i x_i xi与其对应的概率 p i p_i pi的乘积之和称为该离散型随机变量的期望,即 E ( x ) = ∑ i = 1 n x i p i E(x)=\sum_{i=1}^nx_ip_i E(x)=i=1nxipi

题解

先考虑如何计算单点的答案:

首先,该点的初始值只在无赋值操作的时候有效;考虑 n n n个赋值操作将整个操作序列分成了 n + 1 n+1 n+1份,只有最后一个赋值操作有效,所以赋值操作对答案的贡献为 x n \frac{x}{n} nx;只有在最后一个赋值操作之后的加操作有效,所以加操作对答案的贡献为 x n + 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();}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值