codeforces 712E Memory and Casinos

codeforces 712E

题目大意

\(n\)个赌场,在赌场\(i\)\(p_i\)的几率获胜并走到第\(i+1\)个赌场,有\(1-p_i\)的几率失败并走到第\(i-1\)个赌场。有两种操作:

  1. 修改\(p_i\)
  2. 给定区间\([l,r]\),求从\(l\)开始并在\(r\)获胜的概率。

思路

考虑每一个查询操作,对于区间\([l,r]\)\(l\)到达不了\(r\)当且仅当经过足够多的移动之后移动到了第\(l-1\)个赌场,否则一定会移动到\(r\)。那么就能很容易地设计出一个\(O(qn)\)的算法。

我们再考虑两个区间\([l,mid],[mid+1,r]\),我们尝试合并这两个区间,使得最终可以\(O(log_2n)\)的修改和查询。那么我们需要知道哪些信息呢?因为需要在两个区间之间移动,所以我们维护:

  1. 区间\([l,r]\)上从\(l\)开始并在\(r\)获胜的概率,用\(p_{l,r}\)表示。
  2. 区间\([l,r]\)上从\(r\)开始并移动到右边区间的概率,用\(q_{l,r}\)表示。

那么有:
\[ p_{l,r}=\frac{p_{l,mid}p_{mid+1,r}}{1+q_{l,mid}(1-p_{mid+1,r})} \]
\[ q_{l,r}=q_{mid+1,r}+\frac{q_{l,mid}p_{mid+1,r}(1-q_{mid+1,r})}{1-q_{l,mid}(1-p_{mid+1,r})} \]

这个过程可以用线段树维护

提示

等比数列公式:
\[ \sum_{i=0}^{\infty}{p^i}=\frac{1}{1-p} \]

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long double extended;
const int MAXN = 100000 + 10;

struct SegmentTree {
    struct Node {
        extended l, r;
        Node (extended l=0, extended r=0): l(l), r(r) {}
        Node operator+(const Node& a)
        {
            return Node(
                l * a.l / (1 - r * (1 - a.l)),
                a.r + (r * a.l * (1 - a.r)) / (1 - r * (1 - a.l))
            );
        }
    } p[MAXN << 2];
    void pushup(int o) { p[o] = p[o<<1] + p[o<<1|1]; }
    int L[MAXN << 2], R[MAXN << 2];
    void build(int l, int r, int* x, int* y, int o=1)
    {
        L[o] = l, R[o] = r;
        if (l == r) {
            p[o] = Node(
                (extended)x[l] / (extended)y[l],
                (extended)x[l] / (extended)y[l]
            );
            return;
        }
        int mid = (l + r) >> 1;
        build(l, mid, x, y, o<<1);
        build(mid+1, r, x, y, o<<1|1);
        pushup(o);
    }
    void update(int pos, int x, int y, int o=1)
    {
        if (L[o] == pos && pos == R[o]) {
            p[o] = Node(
                (extended)x / (extended)y,
                (extended)x / (extended)y
            );
            return;
        }
        int mid = (L[o] + R[o]) >> 1;
        if (pos <= mid)
            update(pos, x, y, o<<1);
        else
            update(pos, x, y, o<<1|1);
        pushup(o);
    }
    Node query(int l, int r, int o=1)
    {
        if (L[o] == l && r == R[o])
            return p[o];
        int mid = (L[o] + R[o]) >> 1;
        if (r <= mid)
            return query(l, r, o<<1);
        if (mid < l)
            return query(l, r, o<<1|1);
        return query(l, mid, o<<1) + query(mid+1, r, o<<1|1);
    }
    extended solve(int l, int r) { return query(l, r).l; }
} segt;

int main()
{
    ios::sync_with_stdio(0);
    static int X[MAXN], Y[MAXN];
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> X[i] >> Y[i];
    }
    segt.build(1, n, X, Y);
    while (m--) {
        int opt; cin >> opt;
        if (opt == 1) {
            int i, x, y;
            cin >> i >> x >> y;
            segt.update(i, x, y);
        } else {
            int l, r;
            cin >> l >> r;
            cout << segt.solve(l, r) << endl;
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/erro/p/9037229.html