洛谷P4588 [TJOI2018]数学计算

解题报告

发现这个过程用操作序列描述起来比较清晰

比如一溜乘法操作

1 2
1 2
1 4
1 6
2 3

前四个操作就可以描述成

x = 1
| *2
x = 2
| *4
x = 8
| *6
x = 48

而除法操作就是把对应操作序号删掉,换句话说,把乘数改成 1

x = 1
| *2
x = 2
| *1
x = 2
| *6
x = 12

接下来把操作序列横着画

1 1 1 1 1 1 1 ... x = 1
2 4 6 1 1 1 1 ... x = 2 * 4 * 6 = 48
2 1 6 1 1 1 1 ... x = 2 * 1 * 6 = 12

发现这不就是个前缀积吗!

于是题目转化成了:

给定一个全为 1 的序列,每次修改一个数,求前缀积。

线段树一波搞定。

代码实现

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>

#define forall(G,i) for (int i = 0, __for_siz__ = (int) (G).size(); i < __for_siz__; ++i) 
#define DEBUG(x) std::cerr << #x << " = " << x << std::endl;
#define ALL(x) (x).begin(), (x).end()
#define MP std::make_pair
#define se second
#define fi first

using std::cin;
using std::cout;
using std::endl;

inline int read() {
    int s = 0, x = 1; char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') x = -x; ch = getchar(); }
    while (isdigit(ch)) { s = s * 10 + ch - '0'; ch = getchar(); }
    return s * x;
}

int Q, M;

struct SegmentTree {
    static const int MAXQ = 100000 + 10;

#define ls ((p) << 1)
#define rs ((p) << 1 | 1)

    int mul[MAXQ << 2];

    SegmentTree() {}
    
    void Update(int p) {
        mul[p] = (long long int) mul[ls] * (long long int) mul[rs] % M;
    }

    void buildTree(int p, int l, int r) {
        if (l == r) {
            mul[p] = 1; return;
        } int mid = (l + r) >> 1;
        buildTree(ls, l, mid); buildTree(rs, mid + 1, r);
        Update(p);
    }

    void Modify(int p, int l, int r, int pos, int k) {
        if (l == r) {
            mul[p] = k % M; return;
        } int mid = (l + r) >> 1;
        if (pos <= mid) Modify(ls, l, mid, pos, k);
        else Modify(rs, mid + 1, r, pos, k);
        Update(p);
    }

    int Query(int p, int l, int r, int ll, int rr) {
        if (l == ll && rr == r) return mul[p];
        int mid = (l + r) >> 1;
        if (rr <= mid) return Query(ls, l, mid, ll, rr);
        else if (mid + 1 <= ll) return Query(rs, mid + 1, r, ll, rr);
        else return (long long int) Query(ls, l, mid, ll, mid) 
                    * (long long int) Query(rs, mid + 1, r, mid + 1, rr) % M;
    }
} segt;

int T;

int main() {
    T = read();
    while (T --> 0) {
        Q = read(); M = read();
        segt.buildTree(1, 1, Q);
        for (int i = 1; i <= Q; ++i) {
            int op = read(); int m = read();
            if (op == 1) segt.Modify(1, 1, Q, i, m);
            else segt.Modify(1, 1, Q, m, 1);
            printf("%d
", segt.Query(1, 1, Q, 1, Q));

            // for (int i = 1; i <= 20; ++i) printf("%d%c", segt.mul[i], i == 20 ? '
' : ' ');
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/handwer/p/14681644.html