CF712E Memory and Casinos(期望+线段树)

题目大意:

  在这里插入图片描述
(图片翻译来源于:洛谷)

解题思路:

  最后的最后还是看了CF的官方题解…

  1. L [ l , r ] L[l, r] L[l,r]代表从 l l l离开区间的概率
  2. R [ l , r ] R[l,r] R[l,r]代表从 r r r离开区间的概率
  3. l 1 = L [ l , i ] , l 2 = L [ i + 1 , r ] , l e f = L [ l , r ] l1=L[l,i],l2=L[i+1,r],lef=L[l,r] l1=L[l,i],l2=L[i+1,r],lef=L[l,r]
  4. r 1 = R [ l , i ] , r 2 = [ i + 1 , r ] , r i g = R [ l , r ] r1=R[l,i],r2=[i+1,r],rig=R[l,r] r1=R[l,i],r2=[i+1,r],rig=R[l,r]

在这里插入图片描述
在这里插入图片描述

  1. 线段树保存+单点修改+询问(询问与正常线段树有点差别,因为合并规则不同)即可

AC代码:

// 712E — Memory and Casinos(期望).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <iomanip>
#include <cstdio>
//#include <bits/stdc++.h>
using namespace std;
const int maxn = 100100;
pair <double, double> seg[maxn << 2];
double p[maxn];
int n, q;
bool Judge(double x) {
	return fabs(x) <= 0.0000000001;
}
pair <double, double> merge(pair <double, double> a, pair <double, double> b) {
	double l1 = a.first, r1 = a.second;
	double l2 = b.first, r2 = b.second;
	if (Judge(l1 + 1) && Judge(r1 + 1)) return b;//这里返回是因为,该段区间并不在所求区间内
	if (Judge(l2 + 1) && Judge(r2 + 1)) return a;
	if (Judge(((l2 - 1) * r1 + 1))) return make_pair(0, 0);//判断分母是否为0
	double lef = l1 * l2 / ((l2 - 1) * r1 + 1);
	double rig = r2 + (r1 * l2 * (1 - r2)) / (1 - r1 * (1 - l2));
	return make_pair(lef, rig);
}
void build(int lef, int rig, int rt) {
	if (lef == rig) {
		seg[rt] = make_pair(p[lef], p[lef]);//初始都为p[lef]
		return;
	}
	int mid = (lef + rig) >> 1;
	build(lef, mid, rt << 1);
	build(mid + 1, rig, rt << 1 | 1);
	seg[rt] = merge(seg[rt << 1], seg[rt << 1 | 1]);
}
void update(int lef, int rig, int x, double val, int rt) {
	if (x < lef || x > rig) return;
	if (lef == rig) {
		seg[rt] = make_pair(val, val);
		return;
	}
	int mid = (lef + rig) >> 1;
	update(lef, mid, x, val, rt << 1);
	update(mid + 1, rig, x, val, rt << 1 | 1);
	seg[rt] = merge(seg[rt << 1], seg[rt << 1 | 1]);
}
pair <double, double> query(int L, int R, int lef, int rig, int rt) {
	if (R < lef || L > rig) return make_pair(-1, -1);//不在该段区间
	if (L <= lef && rig <= R) {
        return seg[rt];
	}
	int mid = (lef + rig) >> 1;
	return merge(query(L, R, lef, mid, rt << 1), query(L, R, mid + 1, rig, rt << 1 | 1));
	//因为找到的子区间要重新合并,合并规则并不是简单相加,所以这里需要调用函数
}
int main()
{
	int x, y;
	cin >> n >> q;
	for (int i = 1; i <= n; i++) {
		cin >> x >> y;
		p[i] = (double)x / (double)y;
	}
	build(1, n, 1);
    int a, b, c, d;
	for (int i = 1; i <= q; i++) {
		cin >> a >> b >> c;
		//scanf_s("%d%d%d", &a, &b, &c);
		if (a == 1) {
			cin >> d;
			//scanf_s("%d", &d);
			update(1, n, b, (double)c / (double)d, 1);
		}
		else {
			printf("%.20f\n", query(b, c, 1, n, 1).first);
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值