1 条题解

  • 0
    @ 2025-11-18 9:37:42

    题目大意

    我们有一个天平系统,由 NN 个天平和 N+1N+1 个砝码组成。每个天平有两个盘子,盘子上可以放其他天平或砝码。系统构成一棵树,根是天平 1。

    定义:

    • 平衡:天平左右盘子总质量相等
    • 超平衡:天平平衡,且两个盘子上要么都是超平衡的天平,要么都是砝码

    有两种操作:

    1. 修改某个砝码的质量
    2. 查询:为了让天平 ss 变成超平衡的,可以任意增加砝码质量,求天平 ss 上的最小总质量(对 998244353998244353 取模)

    解题思路

    关键观察

    1. 天平结构:整个系统构成一棵有根树,天平是节点,砝码是叶子
    2. 超平衡条件:一个天平要超平衡,必须满足:
      • 左右子树质量相等
      • 左右子树要么都是天平(且都超平衡),要么都是砝码
    3. 最小质量:我们可以通过增加砝码质量来满足平衡条件,目标是总质量最小

    核心思想

    对于每个天平 uu,定义:

    • dp[u]dp[u]:让天平 uu 超平衡所需的最小总质量
    • mul[u]mul[u]:质量乘数,表示为了平衡,需要将基础质量放大的倍数

    递推关系

    • 如果天平 uu 的两个盘子都是砝码:dp[u]=2×max(wL,wR)dp[u] = 2 \times \max(w_L, w_R)
    • 如果天平 uu 的两个盘子都是天平:dp[u]=2×max(dp[L],dp[R])dp[u] = 2 \times \max(dp[L], dp[R])
    • 如果一个盘子是天平,一个是砝码:dp[u]=2×max(dp[L],wR)dp[u] = 2 \times \max(dp[L], w_R)

    但这样还不够,因为我们需要考虑质量放大的倍数关系。

    数学建模

    更精确的模型:

    • 每个天平对应一个方程:左质量 = 右质量
    • 砝码的初始质量已知,但可以增加
    • 目标是让某个天平超平衡,且总质量最小

    实际上,我们可以自底向上计算:

    1. 对于叶子节点(砝码),最小质量就是当前质量
    2. 对于天平节点,设左右子树的最小质量分别为 LLRR
    3. 要让天平平衡,需要满足:kL=mRk \cdot L = m \cdot R,其中 k,mk, m 是正整数
    4. 最小化 kL+mRk \cdot L + m \cdot R,即 2lcm(L,R)2 \cdot \text{lcm}(L, R)

    但这样数值会很大,我们需要在模意义下计算。

    模运算技巧

    由于结果要对 998244353998244353 取模,且题目保证结果是整数,我们可以用模逆元来处理除法。

    定义 f(u)f(u) 为让天平 uu 超平衡的最小总质量,则:

    • 如果 uu 的两个孩子都是砝码:f(u)=2×max(wa,wb)f(u) = 2 \times \max(w_a, w_b)
    • 如果 uu 的两个孩子都是天平:f(u)=2×lcm(f(a),f(b))f(u) = 2 \times \text{lcm}(f(a), f(b))
    • 混合情况类似处理

    但直接计算 lcm 会溢出,我们需要用质因数分解或其他技巧。

    实际实现

    更实用的方法是:定义 val[u]val[u] 为让天平 uu 超平衡时,每个"单位"对应的质量。

    具体步骤:

    1. 建立天平树结构
    2. DFS 预处理每个节点的类型和依赖关系
    3. 对于查询,从目标节点向上计算最小质量
    4. 使用模运算避免溢出

    代码实现

    #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

    优化

    上述直接实现对于大数据会超时,需要优化:

    1. 使用记忆化搜索避免重复计算
    2. 只重新计算受影响的节点
    3. 使用更高效的数据结构

    总结

    这道题的关键在于:

    1. 理解天平系统的树形结构
    2. 掌握超平衡的递归定义
    3. 使用数学方法计算最小质量
    4. 处理模运算下的计算

    算法核心是树形DP结合数论知识,时间复杂度优化后可达 O((N+Q)logN)O((N+Q)\log N)

    • 1

    信息

    ID
    5412
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者