【LOJ2263】「CTSC2017」遊戲
阿新 • • 發佈:2018-11-19
【題目連結】
【思路要點】
- 仿照題目的第二問的解法,我們先來考慮本題的平方做法。
- 令 表示事件 ; 表示事件 ,其中 是 之前第一個確定的事件,若 之前沒有確定的事件,則 ; 表示事件 ,其中 是 之後第一個確定的事件,若 之後沒有確定的事件,則 。
- 我們希望計算概率 ,根據貝葉斯公式:
- 區間 的貢獻即為 ,該式可以看做從事件 轉移到事件 的每一條路徑中,每經過一次 就使計數器 加 ,最後到達 時 值的期望,可以用線段樹維護矩陣做到 查詢。
- 每次單點插入/刪除時在 中找前驅後繼,更新答案即可。
- 時間複雜度 。
【程式碼】
#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; }