题目大意;
维护一个数列,多个操作,有2种,
1.查询当前数列中末尾
L
L
L个数中的最大的数,并输出。
2.给出数
n
u
m
num
num加上上一次查询的数(未查询过不用加上)然后对给定模数
D
D
D取模,所得答案插到数列末尾。
n
u
m
num
num为整数(可能为负数)并且在长整范围内。
初始时数列为空,
M
M
M为操作数,
M
≤
2
∗
1
0
5
M≤2*10^5
M≤2∗105
L
L
L不超过当前数列的长度且
L
>
0
L>0
L>0
模数
D
D
D满足
0
≤
D
≤
2
∗
1
0
9
0≤D≤2*10^9
0≤D≤2∗109
分析:
倍增的思想,
令
f
i
,
j
f_{i,j}
fi,j表示
[
i
−
2
j
−
1
+
1
,
i
]
[i-2^{j-1}+1,i]
[i−2j−1+1,i]的最大值,
然后
O
(
l
o
g
n
)
O(logn)
O(logn)的修改跟查询
注意必要的
l
o
n
g
l
o
n
g
longlong
longlong
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
#define N 200005
using namespace std;
typedef long long ll;
ll f[N][25], now, num, mo;
int n, cnt, lim;
ll Work(int L, int R)
{
if (L == R) { now = f[L][0]; return now; }
for (int i = 25; i >= 0; i--)
if (L + (1 << i) - 1 <= R) { now = max(f[R][i], f[L + (1 << i) - 1][i]); break; }
return now;
}
int main()
{
scanf("%d %lld", &n, &mo);
for (int k = 1; k <= n; k++)
{
char opt[5];
scanf("%s", opt);
if (opt[0] == 'A')
{
scanf("%lld", &num);
f[++cnt][0] = (num + now) % mo;
for(int i = 1; cnt - (1 << i) >= 0; i++) f[cnt][i] = max(f[cnt][i - 1], f[cnt - (1 << (i - 1))][i - 1]);
}
else
{
scanf("%d", &lim);
printf("%lld\n", Work(cnt - lim + 1, cnt));
}
}
return 0;
}