NC20164 [JSOI2008]最大数MAXNUMBER

发布时间 2023-04-25 21:15:35作者: 空白菌

题目链接

题目

题目描述

现在请求你维护一个数列,要求提供以下两种操作:

1、 查询操作。语法:Q L 功能:查询当前数列中末尾L 个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。

2、 插入操作。语法:A n 功能:将n加 上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。

注意:初始时数列是空的,没有一个数。

输入描述

第一行两个整数,M和D,其中M表示操作的个数(M ≤ 200,000),D如上文中所述,满足D在longint内。
接下来M行,查询操作或者插入操作。

输出描述

对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数。

示例1

输入

5 100
A 96
Q 1
A 97
Q 1
Q 2

输出

96
93
96

备注

对于全部的测试点,保证 \(1 \leq M \leq 2 \times 10^5,1 \leq D \leq 2 \times 10^9\)

题解

方法一

知识点:线段树。

可以先开满空间,之后就是普通的单点修改、区间查询了。

时间复杂度 \(O(m \log m)\)

空间复杂度 \(O(m)\)

方法二

知识点:ST表。

因为修改操作是追加形式的,同样可以写成向前合并的ST表,维护向后追加。

时间复杂度 \(O(m \log m)\)
空间复杂度 \(O(m)\)

代码

方法一

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct T {
    ll mx;
    static T e() { return { 1LL << 63 }; }
    friend T operator+(const T &a, const T &b) { return { max(a.mx, b.mx) }; }
};
struct F {
    ll upd;
    T operator()(const T &x) { return { upd }; }
};
template<class T, class F>
class SegmentTree {
    int n;
    vector<T> node;

    void update(int rt, int l, int r, int x, F f) {
        if (r < x || x < l)return;
        if (l == r) return node[rt] = f(node[rt]), void();
        int mid = l + r >> 1;
        update(rt << 1, l, mid, x, f);
        update(rt << 1 | 1, mid + 1, r, x, f);
        node[rt] = node[rt << 1] + node[rt << 1 | 1];
    }

    T query(int rt, int l, int r, int x, int y) {
        if (r < x || y < l) return T::e();
        if (x <= l && r <= y) return node[rt];
        int mid = l + r >> 1;
        return query(rt << 1, l, mid, x, y) + query(rt << 1 | 1, mid + 1, r, x, y);
    }

public:
    SegmentTree(int _n = 0) { init(_n); }

    void init(int _n) {
        n = _n;
        node.assign(n << 2, T::e());
    }

    void update(int x, F f) { update(1, 1, n, x, f); }

    T query(int x, int y) { return query(1, 1, n, x, y); }
};

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int m, d;
    cin >> m >> d;
    SegmentTree<T, F> sgt(m);
    int cnt = 0;
    ll t = 0;
    while (m--) {
        char op;
        int x;
        cin >> op >> x;
        if (op == 'A') sgt.update(++cnt, { ((t + x) % d + d) % d });
        else cout << (t = sgt.query(cnt - x + 1, cnt).mx) << '\n';
    }
    return 0;
}

方法二

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

ll node[21][200007];//! 这里是往前走的,标准st表是往后走的

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int m, d;
    cin >> m >> d;
    int cnt = 0;
    ll t = 0;
    while (m--) {
        char op;
        int x;
        cin >> op >> x;
        if (op == 'A') {
            node[0][++cnt] = ((t + x) % d + d) % d;
            for (int i = 1;i <= 20 && cnt - (1 << i) + 1 >= 1;i++)
                node[i][cnt] = max(node[i - 1][cnt - (1 << i - 1)], node[i - 1][cnt]);
        }
        else {
            int k = log2(x);
            cout << (t = max(node[k][cnt - x + 1 + (1 << k) - 1], node[k][cnt])) << '\n';
        }
    }
    return 0;
}