1 条题解
-
0
题目大意
我们有一个天平系统,由 个天平和 个砝码组成。每个天平有两个盘子,盘子上可以放其他天平或砝码。系统构成一棵树,根是天平 1。
定义:
- 平衡:天平左右盘子总质量相等
- 超平衡:天平平衡,且两个盘子上要么都是超平衡的天平,要么都是砝码
有两种操作:
- 修改某个砝码的质量
- 查询:为了让天平 变成超平衡的,可以任意增加砝码质量,求天平 上的最小总质量(对 取模)
解题思路
关键观察
- 天平结构:整个系统构成一棵有根树,天平是节点,砝码是叶子
- 超平衡条件:一个天平要超平衡,必须满足:
- 左右子树质量相等
- 左右子树要么都是天平(且都超平衡),要么都是砝码
- 最小质量:我们可以通过增加砝码质量来满足平衡条件,目标是总质量最小
核心思想
对于每个天平 ,定义:
- :让天平 超平衡所需的最小总质量
- :质量乘数,表示为了平衡,需要将基础质量放大的倍数
递推关系:
- 如果天平 的两个盘子都是砝码:
- 如果天平 的两个盘子都是天平:
- 如果一个盘子是天平,一个是砝码:
但这样还不够,因为我们需要考虑质量放大的倍数关系。
数学建模
更精确的模型:
- 每个天平对应一个方程:左质量 = 右质量
- 砝码的初始质量已知,但可以增加
- 目标是让某个天平超平衡,且总质量最小
实际上,我们可以自底向上计算:
- 对于叶子节点(砝码),最小质量就是当前质量
- 对于天平节点,设左右子树的最小质量分别为 和
- 要让天平平衡,需要满足:,其中 是正整数
- 最小化 ,即
但这样数值会很大,我们需要在模意义下计算。
模运算技巧
由于结果要对 取模,且题目保证结果是整数,我们可以用模逆元来处理除法。
定义 为让天平 超平衡的最小总质量,则:
- 如果 的两个孩子都是砝码:
- 如果 的两个孩子都是天平:
- 混合情况类似处理
但直接计算 lcm 会溢出,我们需要用质因数分解或其他技巧。
实际实现
更实用的方法是:定义 为让天平 超平衡时,每个"单位"对应的质量。
具体步骤:
- 建立天平树结构
- DFS 预处理每个节点的类型和依赖关系
- 对于查询,从目标节点向上计算最小质量
- 使用模运算避免溢出
代码实现
#include <bits/stdc++.h> using namespace std; const int MOD = 998244353; const int MAXN = 200005; int n, q; vector<pair<char, int>> children[MAXN]; // 每个天平的左右孩子 long long w[MAXN]; // 砝码质量 // 扩展欧几里得求逆元 long long mod_inv(long long a, long long m = MOD) { long long m0 = m, y = 0, x = 1; if (m == 1) return 0; while (a > 1) { long long q = a / m; long long t = m; m = a % m, a = t; t = y; y = x - q * y; x = t; } if (x < 0) x += m0; return x; } // 计算最小公倍数 (模意义下) long long lcm_mod(long long a, long long b) { long long g = __gcd(a, b); return (a / g % MOD) * (b % MOD) % MOD; } // DFS 计算每个节点的最小质量 pair<long long, long long> dfs(int u) { // first: 最小总质量, second: 乘数因子 if (children[u].empty()) { // 砝码节点 return {w[u], 1}; } auto left = children[u][0]; auto right = children[u][1]; pair<long long, long long> l_val, r_val; if (left.first == 'W') { l_val = {w[left.second], 1}; } else { l_val = dfs(left.second); } if (right.first == 'W') { r_val = {w[right.second], 1}; } else { r_val = dfs(right.second); } // 计算最小质量 long long lcm_val = lcm_mod(l_val.second, r_val.second); long long left_mass = (l_val.first * (lcm_val / l_val.second % MOD)) % MOD; long long right_mass = (r_val.first * (lcm_val / r_val.second % MOD)) % MOD; long long max_mass = max(left_mass, right_mass); long long total_mass = (2 * max_mass) % MOD; return {total_mass, (2 * lcm_val) % MOD}; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); cin >> n >> q; // 读入天平结构 for (int i = 1; i <= n; i++) { char type1, type2; int id1, id2; cin >> type1 >> id1 >> type2 >> id2; children[i].push_back({type1, id1}); children[i].push_back({type2, id2}); } // 读入砝码质量 for (int i = 1; i <= n + 1; i++) { cin >> w[i]; } // 预处理所有节点的答案 vector<long long> ans(n + 1); for (int i = 1; i <= n; i++) { auto res = dfs(i); ans[i] = res.first; } // 处理查询 while (q--) { int op; cin >> op; if (op == 1) { int k, new_w; cin >> k >> new_w; w[k] = new_w; // 重新计算受影响的天平(简化实现:全部重新计算) for (int i = 1; i <= n; i++) { auto res = dfs(i); ans[i] = res.first; } } else { int s; cin >> s; cout << ans[s] << '\n'; } } return 0; }样例分析
对于样例输入:
3 5 S 2 W 2 W 1 S 3 W 4 W 3 3 6 1 1 2 2 2 1 1 3 2 2 1 2 3- 查询
2 2:天平 2 需要质量 6 - 查询
2 1:天平 1 需要质量 12 - 修改
1 3 2:把砝码 3 质量改为 2 - 查询
2 1:现在需要质量 16 - 查询
2 3:天平 3 需要质量 4
优化
上述直接实现对于大数据会超时,需要优化:
- 使用记忆化搜索避免重复计算
- 只重新计算受影响的节点
- 使用更高效的数据结构
总结
这道题的关键在于:
- 理解天平系统的树形结构
- 掌握超平衡的递归定义
- 使用数学方法计算最小质量
- 处理模运算下的计算
算法核心是树形DP结合数论知识,时间复杂度优化后可达 。
- 1
信息
- ID
- 5412
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者