[Codeforces 712E Memory and Casinos]概率+线段树区间合并

[Codeforces 712E Memory and Casinos]概率+线段树区间合并

分类:math probabilities data structures

1. 题目链接

[Codeforces 712E Memory and Casinos]

2. 题意描述

现在n个赌场排成一行。
在第i个赌场,有p[i]的概率获胜,如果此时i=n则结束,否则到达第i+1个点;有(1-p[i])概率失败,如果此时i=1则结束,否则到达第i-1个点。
如果某个人要统治区间[i,j],他需要做到以下三件事:
- 从第i个赌场开始
- 不能在第i个赌场失败
- 最后在第j个赌场获胜

现在有q次操作
- 1 i a b 将第i个赌场的胜率改为p[i]=a/b
- 2 l r 询问这个人统治区间[i,j]的概率

(1n,q100000)

3. 解题思路

看了卿学姐的博客,一下就懂了。
必须涨姿势的一道题啊。
但是,官方题解给的做法,还是不知道怎么算出那个级数。
qsc.png
官方题解:http://codeforces.com/blog/entry/47050

4. 实现代码

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef long double LB;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef pair<LB, LB> PLB;

const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const LB eps = 1e-8;
const int MAXN = 100000 + 5;

PLB X[MAXN << 2];

inline PLB calc(const int& a, const int& b) {
    LB x = (LB) (b - a) / a;
    return make_pair(x, x);
}
inline void pushUp(const int& rt) {
    X[rt].first = X[rt << 1].first * X[rt << 1 | 1].first;
    X[rt].second = X[rt << 1].second + X[rt << 1 | 1].second * X[rt << 1].first;
}
void build(int l, int r, int rt) {
    static int ax, bx;
    if(l == r) {
        scanf("%d %d", &ax, &bx);
        X[rt] = calc(ax, bx);
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    pushUp(rt);
}
void update(const int& p, const PLB& v, int l, int r, int rt) {
    if(l == r) { X[rt] = v; return; }
    int mid = (l + r) >> 1;
    if(p <= mid) update(p, v, l, mid, rt << 1);
    else update(p, v, mid + 1, r, rt << 1 | 1);
    pushUp(rt);
}
PLB query(const int& L, const int& R, int l, int r, int rt) {
    static PLB z = make_pair((LB)1.0, (LB)0.0);
    if(L <= l && r <= R) return X[rt];
    int mid = (l + r) >> 1;
    PLB x = z, y = z, ret;
    if(L <= mid) x = query(L, R, l, mid, rt << 1);
    if(R > mid) y = query(L, R, mid + 1, r, rt << 1 | 1);
    ret.first = x.first * y.first;
    ret.second = x.second + y.second * x.first;
    return ret;
}
int main() {
#ifdef ___LOCAL_WONZY___
    freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
    static int n, q, op, x, ax, bx, lx, rx;
    while(~scanf("%d %d", &n, &q)) {
        build(1, n, 1);
        while(q --) {
            scanf("%d", &op);
            if(op == 1) {
                scanf("%d %d %d", &x, &ax, &bx);
                update(x, calc(ax, bx), 1, n, 1);
            } else {
                scanf("%d %d", &lx, &rx);
                LB ans = query(lx, rx, 1, n, 1).second;
                if(ans != ans) ans = 0.0; /// 判断是不是nan
                else ans = 1 / (1 + ans);
                cout << fixed << setprecision(8) << ans << "\n";
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值