CF EDU 110 D - Playoff Tournament
阿新 • • 發佈:2022-05-15
D - Playoff Tournament
樹形dp
- 將字串顛倒,並把每個結點的左右兒子交換,即可變成二叉樹的形式(本題中讓左右兒子交換)
- 首先 dp 算出當前字串每個結點的答案
- 注意到修改一個結點時只會影響到他上方一條鏈上的結點,數目為 \(logn\) 級別,因此每次修改複雜度為 \(logn\)
#include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <cmath> #define rs (u << 1) #define ls (u << 1 | 1) using namespace std; typedef long long ll; const int N = 1e6 + 10; const ll INF = 1e18; string s; int f[N]; int k, n; int dp(int u) { //注意遞迴出口不要越界字串陣列 if (u > n) return 1; if (f[u] >= 0) return f[u]; if (s[u] == '0') return f[u] = dp(ls); if (s[u] == '1') return f[u] = dp(rs); return f[u] = dp(ls) + dp(rs); } void modify(int u, char c) { if (u <= 0) return; s[u] = c; if (c == '0') f[u] = dp(ls); else if (c == '1') f[u] = dp(rs); else f[u] = dp(ls) + dp(rs); modify(u >> 1, s[u >> 1]); } int main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); memset(f, -1, sizeof f); cin >> k >> s; n = s.size(); reverse(s.begin(), s.end()); s = " " + s; dp(1); int q; cin >> q; while(q--) { int p; char c; cin >> p >> c; modify(n + 1 - p, c); cout << f[1] << endl; } return 0; }