【题目链接】
【思路要点】
- 仿照题目的第二问的解法,我们先来考虑本题的平方做法。
- 令 B B B 表示事件 x i = 1 x_i=1 xi=1 ; A A A 表示事件 x j = c x_j=c xj=c ,其中 j j j 是 i i i 之前第一个确定的事件,若 i i i 之前没有确定的事件,则 j = 0 j=0 j=0 ; C C C 表示事件 x k = c x_k=c xk=c ,其中 k k k 是 i i i 之后第一个确定的事件,若 i i i 之后没有确定的事件,则 k = N + 1 k=N+1 k=N+1 。
- 我们希望计算概率 P ( B ∣ A , C ) P(B|A,C) P(B∣A,C) ,根据贝叶斯公式:
P ( B ∣ A , C ) = P ( A , C ∣ B ) ∗ P ( B ) P ( A , C ) = P ( A ∣ B ) ∗ P ( C ∣ B ) ∗ P ( B ) P ( C ∣ A ) ∗ P ( A ) = P ( B ∣ A ) ∗ P ( C ∣ B ) P ( C ∣ A ) P(B|A,C)=\frac{P(A,C|B)*P(B)}{P(A,C)}=\frac{P(A|B)*P(C|B)*P(B)}{P(C|A)*P(A)}=\frac{P(B|A)*P(C|B)}{P(C|A)} P(B∣A,C)=P(A,C)P(A,C∣B)∗P(B)=P(C∣A)∗P(A)P(A∣B)∗P(C∣B)∗P(B)=P(C∣A)P(B∣A)∗P(C∣B)- 区间 [ j , k ) [j,k) [j,k) 的贡献即为 ∑ i = j k − 1 P ( B ∣ A , C ) = ∑ i = j k − 1 P ( B ∣ A ) ∗ P ( C ∣ B ) P ( C ∣ A ) \sum_{i=j}^{k-1}P(B|A,C)=\frac{\sum_{i=j}^{k-1}P(B|A)*P(C|B)}{P(C|A)} ∑i=jk−1P(B∣A,C)=P(C∣A)∑i=jk−1P(B∣A)∗P(C∣B) ,该式可以看做从事件 A A A 转移到事件 C C C 的每一条路径中,每经过一次 x i = 1 x_i=1 xi=1 就使计数器 c n t cnt cnt 加 1 1 1 ,最后到达 C C C 时 c n t cnt cnt 值的期望,可以用线段树维护矩阵做到 O ( L o g N ) O(LogN) O(LogN) 查询。
- 每次单点插入/删除时在 s e t set set 中找前驱后继,更新答案即可。
- 时间复杂度 O ( N L o g N ) O(NLogN) O(NLogN) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int n, m; char type; double p[MAXN], q[MAXN], t[MAXN][2][2]; struct info {double p[2][2], e[2][2]; }; //0 : lose, 1 : win info cipher() { info ans; memset(ans.p, 0, sizeof(ans.p)); memset(ans.e, 0, sizeof(ans.e)); return ans; } info unit() { info ans = cipher(); ans.p[0][0] = ans.p[1][1] = ans.e[1][1] = 1; return ans; } info merge(info a, info b, int pos) { info ans = cipher(); for (int i = 0; i <= 1; i++) for (int j = 0; j <= 1; j++) { for (int k = 0; k <= 1; k++) for (int l = 0; l <= 1; l++) { ans.p[i][j] += a.p[i][k] * t[pos][k][l] * b.p[l][j]; ans.e[i][j] += (a.p[i][k] * t[pos][k][l] * b.p[l][j]) * (a.e[i][k] + b.e[l][j]); } ans.e[i][j] /= ans.p[i][j]; } return ans; } struct SegmentTree { struct Node { int lc, rc; info ans; } a[MAXN * 2]; int n, size, root; void update(int root, int l, int r) { int mid = (l + r) / 2; a[root].ans = merge(a[a[root].lc].ans, a[a[root].rc].ans, mid + 1); } void build(int &root, int l, int r) { root = ++size; if (l == r) { a[root].ans = unit(); return; } int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); update(root, l, r); } void init(int x) { n = x; root = size = 0; build(root, 0, n); } info query(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) return a[root].ans; int mid = (l + r) / 2; if (mid >= qr) return query(a[root].lc, l, mid, ql, qr); else if (mid + 1 <= ql) return query(a[root].rc, mid + 1, r, ql, qr); else return merge(query(a[root].lc, l, mid, ql, mid), query(a[root].rc, mid + 1, r, mid + 1, qr), mid + 1); } info query(int l, int r) { return query(root, 0, n, l, r); } double getans(pair <int, int> x, pair <int, int> y) { info tmp = query(x.first, y.first); return tmp.e[x.second][y.second] - y.second; } } ST; set <pair <int, int> > st; int main() { scanf("%d%d %c", &n, &m, &type); for (int i = 1; i <= n; i++) { scanf("%lf", &p[i]); if (i == 1) q[i] = p[i]; else scanf("%lf", &q[i]); t[i][0][0] = 1 - q[i]; t[i][0][1] = q[i]; t[i][1][0] = 1 - p[i]; t[i][1][1] = p[i]; } t[n + 1][0][0] = t[n + 1][1][0] = 1; ST.init(n + 1); st.insert(make_pair(0, 0)); st.insert(make_pair(n + 1, 0)); double now = ST.getans(make_pair(0, 0), make_pair(n + 1, 0)); cerr << now << endl; for (int i = 1; i <= m; i++) { char opt[15]; int x; scanf("\n%s%d", opt, &x); if (opt[0] == 'a') { int y; read(y); pair <int, int> tmp = make_pair(x, y); auto suf = st.lower_bound(tmp), pre = suf; pre--; now -= ST.getans(*pre, *suf); now += ST.getans(*pre, tmp); now += ST.getans(tmp, *suf); st.insert(tmp); } else { pair <int, int> tmp = make_pair(x, 0); auto pos = st.lower_bound(tmp), pre = pos, suf = pos; suf++, pre--; now += ST.getans(*pre, *suf); now -= ST.getans(*pre, *pos); now -= ST.getans(*pos, *suf); st.erase(pos); } printf("%.10lf\n", now); } return 0; }