Submission #1312969

#TimeUsernameProblemLanguageResultExecution timeMemory
13129694QT0RSumtree (INOI20_sumtree)C++20
100 / 100
502 ms65972 KiB
// gemini code for testing #include <iostream> #include <vector> #include <algorithm> #include <random> using namespace std; // --- Constants --- const int MOD = 1e9 + 7; const int MAXN = 200005; // Max value for combinations is R + N approx 3e5 + 2e5 = 5e5 const int MAX_FACT = 600005; // --- Math Helpers --- long long fact[MAX_FACT], invFact[MAX_FACT]; long long power(long long base, long long exp) { long long res = 1; base %= MOD; while (exp > 0) { if (exp % 2 == 1) res = (res * base) % MOD; base = (base * base) % MOD; exp /= 2; } return res; } long long modInverse(long long n) { return power(n, MOD - 2); } void precomputeFactorials() { fact[0] = 1; invFact[0] = 1; for (int i = 1; i < MAX_FACT; i++) { fact[i] = (fact[i - 1] * i) % MOD; } invFact[MAX_FACT - 1] = modInverse(fact[MAX_FACT - 1]); for (int i = MAX_FACT - 2; i >= 0; i--) { invFact[i] = (invFact[i + 1] * (i + 1)) % MOD; } } long long nCr(int n, int r) { if (r < 0 || r > n) return 0; return (((fact[n] * invFact[r]) % MOD) * invFact[n - r]) % MOD; } // --- Tree Data --- vector<int> adj[MAXN]; int tin[MAXN], tout[MAXN], sub_sz[MAXN], depth[MAXN], parent[MAXN]; int timer; int n, r_initial; void dfs(int u, int p, int d) { tin[u] = ++timer; sub_sz[u] = 1; depth[u] = d; parent[u] = p; for (int v : adj[u]) { if (v != p) { dfs(v, u, d + 1); sub_sz[u] += sub_sz[v]; } } tout[u] = timer; } // --- Treap (for managing children lists) --- struct TreapNode { int id; // Vertex ID int priority; int key; // Uses tin[id] as key int l, r; // Aggregates long long sum_val; // Sum of tag values long long sum_sz; // Sum of subtree sizes // Values of this specific node long long self_val; long long self_sz; } tree[MAXN]; int root_treap[MAXN]; // The Treap Root for each fixed node mt19937 rng(1337); void update_treap_node(int t) { if (!t) return; tree[t].sum_val = tree[t].self_val; tree[t].sum_sz = tree[t].self_sz; if (tree[t].l) { tree[t].sum_val += tree[tree[t].l].sum_val; tree[t].sum_sz += tree[tree[t].l].sum_sz; } if (tree[t].r) { tree[t].sum_val += tree[tree[t].r].sum_val; tree[t].sum_sz += tree[tree[t].r].sum_sz; } } void split(int t, int key, int &l, int &r) { if (!t) { l = r = 0; return; } if (tree[t].key <= key) { split(tree[t].r, key, tree[t].r, r); l = t; } else { split(tree[t].l, key, l, tree[t].l); r = t; } update_treap_node(t); } void merge(int &t, int l, int r) { if (!l || !r) t = l ? l : r; else if (tree[l].priority > tree[r].priority) { merge(tree[l].r, tree[l].r, r); t = l; } else { merge(tree[r].l, l, tree[r].l); t = r; } update_treap_node(t); } // --- HLD + SegTree (for Nearest Fixed Ancestor) --- int head[MAXN], pos[MAXN], hld_sz[MAXN]; pair<int, int> seg[4 * MAXN]; // Stores {depth, node_index} int cur_pos = 0; void dfs_hld(int u) { hld_sz[u] = 1; int max_sz = 0, big_child = -1; for (int &v : adj[u]) { if (v != parent[u]) { dfs_hld(v); hld_sz[u] += hld_sz[v]; if (hld_sz[v] > max_sz) { max_sz = hld_sz[v]; big_child = v; } } } // Optimization: move heavy child to front // (Omitted for brevity, standard HLD optimization) } void decompose(int u, int h) { head[u] = h; pos[u] = ++cur_pos; int big_child = -1, max_sz = -1; for (int v : adj[u]) { if (v != parent[u] && hld_sz[v] > max_sz) { max_sz = hld_sz[v]; big_child = v; } } if (big_child != -1) decompose(big_child, h); for (int v : adj[u]) { if (v != parent[u] && v != big_child) { decompose(v, v); } } } void update_seg(int node, int start, int end, int idx, pair<int, int> val) { if (start == end) { seg[node] = val; return; } int mid = (start + end) / 2; if (idx <= mid) update_seg(node * 2, start, mid, idx, val); else update_seg(node * 2 + 1, mid + 1, end, idx, val); seg[node] = max(seg[node * 2], seg[node * 2 + 1]); } pair<int, int> query_seg(int node, int start, int end, int l, int r) { if (r < start || end < l) return {-1, -1}; if (l <= start && end <= r) return seg[node]; int mid = (start + end) / 2; return max(query_seg(node * 2, start, mid, l, r), query_seg(node * 2 + 1, mid + 1, end, l, r)); } int get_nearest_fixed_ancestor(int u) { pair<int, int> res = {-1, -1}; while (u != -1) { // -1 when we go above root, but loop condition handles head[u] logic res = max(res, query_seg(1, 1, n, pos[head[u]], pos[u])); if (head[u] == 1) break; // Reached root chain u = parent[head[u]]; } return res.second; } // --- Global Answer Management --- long long current_ans = 1; int zero_count = 0; long long node_ways[MAXN]; bool is_fixed[MAXN]; long long fixed_val[MAXN]; long long calculate_ways(int u) { long long load = 0; long long size_deduction = 0; if (root_treap[u]) { load = tree[root_treap[u]].sum_val; size_deduction = tree[root_treap[u]].sum_sz; } long long rem = fixed_val[u] - load; long long scope_size = sub_sz[u] - size_deduction; if (rem < 0) return 0; // Stars and bars: (Slack + ScopeSize - 1) choose (ScopeSize - 1) return nCr(rem + scope_size - 1, scope_size - 1); } void update_global_ans(int u, bool adding) { long long w = node_ways[u]; if (!adding) { if (w == 0) zero_count--; else current_ans = (current_ans * modInverse(w)) % MOD; } else { w = calculate_ways(u); node_ways[u] = w; if (w == 0) zero_count++; else current_ans = (current_ans * w) % MOD; } } // --- Main --- int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); precomputeFactorials(); if (!(cin >> n >> r_initial)) return 0; for (int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); } dfs(1, -1, 0); dfs_hld(1); decompose(1, 1); // Init Segment Tree for(int i=0; i<4*MAXN; i++) seg[i] = {-1, -1}; // Init Treap Nodes for(int i=1; i<=n; i++) { tree[i].id = i; tree[i].priority = rng(); tree[i].key = tin[i]; tree[i].l = tree[i].r = 0; tree[i].self_val = 0; tree[i].self_sz = sub_sz[i]; // Initial full subtree size update_treap_node(i); } // Set up Root is_fixed[1] = true; fixed_val[1] = r_initial; tree[1].self_val = r_initial; update_treap_node(1); update_seg(1, 1, n, pos[1], {depth[1], 1}); update_global_ans(1, true); cout << (zero_count > 0 ? 0 : current_ans) << "\n"; int q; cin >> q; while(q--) { int type; cin >> type; if (type == 1) { // Add Tag int u, val; cin >> u >> val; // 1. Find Ancestor int anc = get_nearest_fixed_ancestor(u); // 2. Remove Anc from answer update_global_ans(anc, false); // 3. Extract children from Anc that belong to U // U's subtree range is [tin[u], tout[u]] // Treap is sorted by tin. Just split by range. int t_anc = root_treap[anc]; int l, m, r_part; split(t_anc, tout[u], m, r_part); // m has keys <= tout[u] split(m, tin[u]-1, l, m); // m has keys >= tin[u] // Now 'm' contains exactly the descendants of u root_treap[u] = m; // 4. Setup U is_fixed[u] = true; fixed_val[u] = val; tree[u].self_val = val; // The treap node for U stores its RAW subtree size. // The deduction happens when calculating 'calculate_ways', not in the node struct itself. tree[u].self_sz = sub_sz[u]; update_treap_node(u); // 5. Insert U into Anc's treap // Reassemble anc: l + u + r_part int temp; merge(temp, l, u); // u is index in tree[] array merge(root_treap[anc], temp, r_part); // 6. Update SegTree update_seg(1, 1, n, pos[u], {depth[u], u}); // 7. Update Global Answers update_global_ans(u, true); update_global_ans(anc, true); } else { // Remove Tag int u; cin >> u; // 1. Get Parent in Fixed Tree // Temporarily unmark u to find its ancestor update_seg(1, 1, n, pos[u], {-1, -1}); int anc = get_nearest_fixed_ancestor(u); // 2. Remove U and Anc from answer // Note: we must remove U from global calc BEFORE unsetting its data update_global_ans(u, false); update_global_ans(anc, false); // 3. Remove U from Anc's treap // U is a direct child in Anc's treap. Isolate it. int t_anc = root_treap[anc]; int l, mid, r_part; split(t_anc, tin[u], mid, r_part); // mid <= tin[u] split(mid, tin[u]-1, l, mid); // mid == u (since key is unique) // 4. Merge U's children back into Anc // U's children are in root_treap[u]. // We merge: l + root_treap[u] + r_part int temp; merge(temp, l, root_treap[u]); merge(root_treap[anc], temp, r_part); // 5. Finalize State is_fixed[u] = false; // SegTree already updated in step 1 // 6. Recalculate Anc update_global_ans(anc, true); } cout << (zero_count > 0 ? 0 : current_ans) << "\n"; } return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...