• 牛客寒假算法基础集训营4 B 进制(线段树)


    进制

    题目大意:

    给出一个数字串,q 次以下两种操作:

    1. 输入 1 x y,修改第 x 个字符为 y
    2. 输出 2 x y ,代表查询区间 [x,y] 子串所能表示的某进制的最小值,对 1e9+7 取模。
    思路:

    要得到最小值,显然进制的选择是区间最大值+1。

    看操作是单点修改和区间查询,我们考虑用线段树来维护区间上 2-10 进制的值以及区间最大值。

    考虑怎样进行区间合并:

    假设当前是十进制

        14352
        /   \
      143   53
    

    \[14352 = 143 * 10^2 + 53 \]

    可以发现区间 k 进制的合并是由 k 进制下 左孩子节点 * k 进制的右孩子节点的数字个数次幂 + 右孩子节点 所得到。我们需要维护 k 进制下每个节点的值,以及左兄弟节点与之合并时需要的幂次。

    进制不合法的情况我们一样可以进行更新操作,因为我们并不会去选用这样的进制,因此其对于我们的结果没有影响。

    在实现上,我们可以通过重载结构体中的加号来进行区间的合并,这样线段树主体的结构显得比较清晰明了,并且容易去修改和调试。

    Code:
    struct Node {
        int mx;
        vector<ll> val, pre;
        Node(int x = 0) : mx(x), val(10 + 1, x), pre(10 + 1) {
            for (int i = 1; i <= 10; i++) {
                pre[i] = i;
            }
        }
        Node operator+(const Node &node) const {
            Node res;
            res.mx = max(mx, node.mx);
            for (int i = 1; i <= 10; i++) {
                res.pre[i] = pre[i] * node.pre[i] % mod;
                res.val[i] = (val[i] * node.pre[i] + node.val[i]) % mod;
            }
            return res;
        }
        ll operator()() const {
            return val[mx + 1];
        }
    };
    
    #define ls (v << 1)
    #define rs (ls | 1)
    #define tm ((tl + tr) >> 1)
    struct Segment {
        int n;
        vector<Node> nodes;
        Segment(string &s) : n((int)s.size()), nodes(n << 2) {
            function<void(int, int, int)> dfs = [&](int v, int tl, int tr) { // 节点标号,维护的区间
                if (tl == tr) {
                    nodes[v] = Node(s[tm - 1] - '0');
                } else {
                    dfs(ls, tl, tm);
                    dfs(rs, tm + 1, tr);
                    nodes[v] = nodes[ls] + nodes[rs];
                }
            };
            dfs(1, 1, n);
        }
        void upd(int x, int y) {
            function<void(int, int, int)> dfs = [&](int v, int tl, int tr) {
                if (tl == tr) {
                    nodes[v] = Node(y);
                } else {
                    if (x <= tm)
                        dfs(ls, tl, tm);
                    else
                        dfs(rs, tm + 1, tr);
                    nodes[v] = nodes[ls] + nodes[rs];
                }
            };
            dfs(1, 1, n);
        }
        ll query(int x, int y) {
            function<Node(int, int, int)> dfs = [&](int v, int tl, int tr) {
                if (x <= tl && tr <= y)
                    return nodes[v];
                if (y <= tm)
                    return dfs(ls, tl, tm);
                if (x > tm)
                    return dfs(rs, tm + 1, tr);
                return dfs(ls, tl, tm) + dfs(rs, tm + 1, tr);
            };
            return dfs(1, 1, n)();
        }
    };
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int n, q;
        cin >> n >> q;
        string s;
        cin >> s;
        Segment seg(s);
        while (q--) {
            int op, x, y;
            cin >> op >> x >> y;
            if (op == 1) {
                seg.upd(x, y);
            } else {
                cout << seg.query(x, y) << "\n";
            }
        }
        return 0;
    }
    
  • 相关阅读:
    非确定的自动机NFA确定化为DFA
    正规式到正规文法与自动机
    第六次 正规文法与正规式
    作业五 词法分析程序的设计与实现
    作业四:
    作业三
    作业2.文法和语言
    编译原理 作业一
    李瑞红201771010111《第三周学习总结》
    李瑞红201771010111第二周实验总结报告
  • 原文地址:https://www.cnblogs.com/Nepenthe8/p/15950320.html
Copyright © 2020-2023  润新知