题目大意:
给定一个空数组,然后操作n次,每次根据输入的字母来决定操作的情况,分为以下两种情况:
1.查询操作:语法:
Q L
功能:查询当前数列中末尾 𝐿L 个数中的最大的数,并输出这个数的值。
限制:𝐿L 不超过当前数列的长度。(𝐿>0)(L>0)
插入操作。
2.插入操作:语法:
A n
功能:将 𝑛n 加上 𝑡t,其中 𝑡t 是最近一次查询操作的答案(如果还未执行过查询操作,则 𝑡=0t=0),并将所得结果对一个固定的常数 𝐷D 取模,将所得答案插入到数列的末尾。
限制:𝑛n 是整数(可能为负数)并且在长整范围内。
注意:初始时数列是空的,没有一个数。
刚开始看到这个题的时候,我无从下手,所以就跳了,后面学了线段树后才发现这个题可以用线段树做,但是没有模板线段树一样代码冗杂,比较简单,考虑到这种情况就容易写出来了,叙述不容易明白,直接看代码更加清楚一点:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e6 + 5;
const ll inf = 1e18;
ll tree[N << 2], tag[N << 2];
ll n, mod, k;
ll pos = 0, t = 0;
int lson(int i) {
return i << 1;
}
int rson(int i) {
return i << 1 | 1;
}
void up(ll i) {
tree[i] = max(tree[lson(i)], tree[rson(i)]);
}
void update(ll i, ll pl, ll pr, ll idx, ll val) {
if (pl == pr) {
tree[i] = val;
return;
}
ll mid = (pl + pr) >> 1;
if (idx <= mid) {
update(lson(i), pl, mid, idx, val);
} else {
update(rson(i), mid + 1, pr, idx, val);
}
up(i);
}
ll query(ll i, ll pl, ll pr, ll L, ll R) {
if (pl >= L && pr <= R) {
return tree[i];
}
ll mid = (pl + pr) >> 1;
ll maxx = -inf;
if (L <= mid) {//直接快速寻找该更新的地址,避免不必要计算
maxx = max(maxx, query(lson(i), pl, mid, L, R));
}
if (R > mid) {
maxx = max(maxx, query(rson(i), mid + 1, pr, L, R));
}
return maxx;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> mod;
ll N = n;
while (n--) {
char op;
cin >> op >> k;
if (op == 'A') {
pos++; // 在添加元素之前增加pos
k += t;
k %= mod;
update(1, 1, N, pos, k); // 使用update函数更新最后一个元素
} else {
t = query(1, 1, N, pos - k + 1, pos);//查询最后k个元素的最大值
cout << t << '\n';
}
}
return 0;
}
可以看到这个代码不需要build函数,laze函数,down函数,代码简洁明了了很多,但是写的时候还是有点困难,可能是我实力不够,感觉这个题还是有难度的,不同于模板1和模板2,虽然代码简单了一些,但是更加难想到,当然肯定有其他解法,比如可以用st表,单调队列等等等等。
那么今天学习到此结束,下次再见吖!