最大数(动态开点)

简介: 笔记

题目描述


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


1、 查询操作。


语法:Q L


功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。


限制:L 不超过当前数列的长度。(L > 0)


2、 插入操作。


语法:A n


功能:将 n 加上 t,其中 t 是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数 D 取模,将所得答案插入到数列的末尾。


限制:n 是整数(可能为负数)并且在长整范围内。


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


输入格式


第一行两个整数,M 和 D,其中 M 表示操作的个数,D 如上文中所述。


接下来的 M 行,每行一个字符串,描述一个具体的操作。语法如上文所述。


输出格式


对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。


输入输出样例

输入 #1


5 100

A 96

Q 1

A 97

Q 1

Q 2


输出 #1


96

93

96


数据范围


0.png


代码


板子题


普通线段树

#include<iostream>
using namespace std;
const int N = 200010;
#define int long long
int m, p;
struct node {
    int l, r;
    int v;
}tr[4 * N];
void pushup(int u) {
    tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
}
void build(int u, int l, int r) {
    tr[u] = {l, r};
    if(l == r) return ;
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    return ;
}
int query(int u, int l, int r) {
    if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
    int mid = tr[u].l + tr[u].r >> 1;
    int v =  0;
    if(l <= mid) v = query(u << 1, l, r);
    if(r > mid) v = max(v, query(u << 1 | 1, l, r));
    return v;
}
void modify(int u, int x, int v) {
    if(tr[u].l == x && tr[u].r == x) tr[u].v = v;
    else {
        int mid = tr[u].l + tr[u].r >> 1;
        if(x <= mid) modify(u << 1, x, v);
        else modify(u << 1 | 1, x, v);
        pushup(u);
    }
    return ;
}
signed main() {
    int n = 0, last = 0;
    cin >> m >> p;
    build(1, 1, m);
    char op; 
    int x; 
    while(m--) {
        cin >> op >> x;
        if(op == 'Q') {
            last = query(1, n - x + 1, n);
            cout << last << endl;
        } else {
            n += 1;
            modify(1, n, (last + x) % p);
        }
    }
    return 0;
}
  • 动态开点
#include <iostream>
using namespace std;
const int N = 200010;
struct node {
    int l, r;
    int s;
} tr[N << 1];
int n, m, mod, last, root, idx;
void pushup(int p) {
    tr[p].s = max(tr[tr[p].l].s, tr[tr[p].r].s);
}
void modify(int &p, int l, int r, int ql, int qr, int x) {
    if(!p) p = ++idx;
    if(l >= ql && r <= qr) {
        tr[p].s = x;
        return ;
    }
    int mid = l + r >> 1;
    if(ql <= mid) modify(tr[p].l, l, mid, ql, qr, x);
    if(qr > mid) modify(tr[p].r, mid + 1, r, ql, qr, x);
    pushup(p);
}
int query(int p, int l, int r, int ql, int qr) {
    if(!p) return 0;
    if(l >= ql && r <= qr) return tr[p].s;
    int mid = l + r >> 1;
    int v = 0;
    if(ql <= mid) v = max(v, query(tr[p].l, l, mid, ql, qr));
    if(qr > mid) v = max(v, query(tr[p].r, mid + 1, r, ql, qr));
    return v;
}
int main()
{
    cin >> m >> mod;
    char op;
    int x;
    while(m--) {
        cin >> op >> x;
        if(op == 'Q') {
            last = query(root, 1, N, n - x + 1, n);
            cout << last << endl;
        }
        if(op == 'A') {
            x = ((long long)x + last) % mod;
            ++n;
            modify(root, 1, N, n, n, x);
        }
    }
    return 0;
}
相关文章
|
C语言
C 语言实例 - 判断三个数中的最大数
C 语言实例 - 判断三个数中的最大数。
155 36
交换两个数的值的方法(三种)
交换两个数的值的方法(三种)
66 1
|
6月前
4.韩信点兵:有一个数,用3除余2;用5除余3;用7除余2,求满足条件的最小数
4.韩信点兵:有一个数,用3除余2;用5除余3;用7除余2,求满足条件的最小数
26 0
|
6月前
|
算法 测试技术 C#
【位运算 试填法】【推荐】3022. 给定操作次数内使剩余元素的或值最小
【位运算 试填法】【推荐】3022. 给定操作次数内使剩余元素的或值最小
|
6月前
1679.K和数对的最大数目
1679.K和数对的最大数目
33 0
|
6月前
|
算法 Java C++
动态求连续区间和
动态求连续区间和
41 0
|
机器学习/深度学习
一道题,最小操作次数使数组元素相等引发的思考
给你一个长度为 n 的整数数组,每次操作将会使 n - 1 个元素增加 1 。返回让数组所有元素相等的最小操作次数。
113 0
一道题,最小操作次数使数组元素相等引发的思考
|
算法 前端开发 JavaScript
【前端算法】在一个数组中找出和为n的两个数
如何实现在一个数组中找出和为n的两个数的过程
101 0
获取最小操作次数使数组元素相等
获取最小操作次数使数组元素相等(算法题)