题面
题目描述
现在请求你维护一个数列,要求提供以下两种操作:
1、 查询操作。
语法:Q L
功能:查询当前数列中末尾 L L L 个数中的最大的数,并输出这个数的值。
限制: L L L 不超过当前数列的长度。 ( L > 0 ) (L > 0) (L>0)
2、 插入操作。
语法:A n
功能:将 n n n 加上 t t t,其中 t t t 是最近一次查询操作的答案(如果还未执行过查询操作,则 t = 0 t=0 t=0),并将所得结果对一个固定的常数 D D D取模,将所得答案插入到数列的末尾。
限制: n n n 是整数(可能为负数)并且在长整范围内。
注意:初始时数列是空的,没有一个数。
输入格式
第一行两个整数, M M M 和 D D D,其中 M M M 表示操作的个数, D D D 如上文中所述。
接下来的 M M M 行,每行一个字符串,描述一个具体的操作。语法如上文所述。
输出格式
对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。
样例 #1
样例输入 #1
5 100
A 96
Q 1
A 97
Q 1
Q 2
样例输出 #1
96
93
96
提示
数据规模与约定
对于全部的测试点,保证 1 ≤ M ≤ 2 × 1 0 5 1 \leq M \leq 2 \times 10^5 1≤M≤2×105, 1 ≤ D ≤ 2 × 1 0 9 1 \leq D \leq 2 \times 10^9 1≤D≤2×109。
思路
不难看出,这题可以使用线段树来做(用于维护区间最大值),我们先建一棵树,让它的所有叶子节点全部都为
0
0
0。当我们每次输入为 A
时,就更改下一个叶子节点,这就变成了单点修改。如果输入为 Q
时,就用区间查找的方法寻找末尾
L
L
L 个数中的最大的数。
建树
inline void make_tree(int q, int l, int r) {//建树
if (l == r) {//如果是叶子节点
tree[q].left = l;//左端为自己的位置
tree[q].right = r;//右端为自己的位置
tree[q].maxnum = 0;//因为还不知到值是多少,先为0,后面再修改
return;
}
int mid = (l + r) >> 1;
//将l~r分成l~mid和(mid+1)~r,类似于分治,利用小问题的解求出大问题
make_tree(q * 2, l, mid);
make_tree(q * 2 + 1, mid + 1, r);
tree[q].left = l;
tree[q].right = r;
tree[q].maxnum = max(tree[q * 2].maxnum, tree[q * 2 + 1].maxnum);
}
单点修改
inline void change(int q, int x, int sum) {//单点修改
if (tree[q].left == x && x == tree[q].right) {//寻找到该点了
tree[q].maxnum += sum;//将值加上,因为初始话为 0,也可以改成tree[q].maxnum = sum
return;
}
if (x >= tree[q * 2 + 1].left)//在右半边
change(q * 2 + 1, x, sum);
else if (x <= tree[q * 2].right)//在左半边
change(q * 2, x, sum);
tree[q].maxnum = max(tree[q * 2].maxnum, tree[q * 2 + 1].maxnum);//更新
}
区间查找
inline int getmax(int q, int l, int r) {//区间查找
if (l == tree[q].left && r == tree[q].right)//找到一块符合的
return tree[q].maxnum;
if (l >= tree[q * 2 + 1].left)//全部都在右半边
return getmax(q * 2 + 1, l, r);
else if (r <= tree[q * 2].right)//全部都在左半边
return getmax(q * 2, l, r);
else//都有
return max(getmax(q * 2, l, tree[q * 2].right), getmax(q * 2 + 1, tree[q * 2 + 1].left, r));
}
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, m;
int last;
struct op {
int left, right, maxnum;
} tree[5000005];
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void make_tree(int q, int l, int r) {//建树
if (l == r) {
tree[q].left = l;
tree[q].right = r;
tree[q].maxnum = 0;
return;
}
int mid = (l + r) >> 1;
make_tree(q * 2, l, mid);
make_tree(q * 2 + 1, mid + 1, r);
tree[q].left = l;
tree[q].right = r;
tree[q].maxnum = max(tree[q * 2].maxnum, tree[q * 2 + 1].maxnum);
}
inline int getmax(int q, int l, int r) {//区间查找
if (l == tree[q].left && r == tree[q].right)
return tree[q].maxnum;
if (l >= tree[q * 2 + 1].left)
return getmax(q * 2 + 1, l, r);
else if (r <= tree[q * 2].right)
return getmax(q * 2, l, r);
else
return max(getmax(q * 2, l, tree[q * 2].right), getmax(q * 2 + 1, tree[q * 2 + 1].left, r));
}
inline void change(int q, int x, int sum) {//单点修改
if (tree[q].left == x && x == tree[q].right) {
tree[q].maxnum += sum;
return;
}
if (x >= tree[q * 2 + 1].left)
change(q * 2 + 1, x, sum);
else if (x <= tree[q * 2].right)
change(q * 2, x, sum);
tree[q].maxnum = max(tree[q * 2].maxnum, tree[q * 2 + 1].maxnum);
}
int www;
signed main() {
n = read(), m = read();
make_tree(1, 1, n);
while (n--) {
char aa = getchar();
if (aa == 'A') {
int xx = read();
xx = (xx + last) % m;
www++;
change(1, www, xx);
} else {
int xx = read();
last = getmax(1, www - xx + 1, www);
printf("%lld\n", last);
}
}
return 0;
}