計蒜客 蒜頭君的任務
題目描述
蒜頭君的上司給蒜頭君佈置了一個任務,蒜頭君維護一個數列,要求提供以下兩種操作:
- 查詢操作。
語法:Q L
功能:查詢當前數列中末尾 個數中的最大的數,並輸出這個數的值。
- 插入操作。
語法:A n
功能:將 加上 ,其中 是最近一次查詢操作的答案(如果還未執行過查詢操作,則 ),並將所得結果對一個固定的常數 取模,將所得答案插入到數列的末尾。
初始時數列是空的,沒有一個數。
樣例
樣例輸入
第一行兩個整數, 和 ,其中 表示操作的個數(), 如上文中所述,滿足 在 位整型範圍內。
接下來 行,查詢操作或者插入操作。
5 100
A 96
Q 1
A 97
Q 1
Q 2
樣例輸出
對於每一個詢問操作,輸出一行。該行只有一個數,即序列中最後 個數的最大數。
96
93
96
算法與數據結構
樹狀數組
區間最值
題解
這道題就是直接套用樹狀數組區間最值的模板。
完整代碼
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 200007;
int A[MAX_N] = {0}; // 輸入數據 A
int C[MAX_N] = {0}; // 樹狀數組 C
int lowBit(int x) {
return x & -x; // return x & (x ^ (x - 1))
}
// 注意哪裏是 A 哪裏是 C
int getMax(int l, int r) {
int ret = A[r];
while (l <= r) {
ret = max(ret, A[r]);
for (--r; r - l >= lowBit(r); r -= lowBit(r))
ret = max(ret, C[r]);
}
return ret;
}
void change(int r) {
C[r] = A[r];
for (int i = 1; i < lowBit(r); i <<= 1)
C[r] = max(C[r], C[r - i]);
}
int main() {
int M, D;
int r = 1; // 樹狀數組下標從 1 開始
int t = 0;
scanf("%d%d", &M, &D);
for (int i = 0; i < M; i++) {
char op;
scanf("\n%c", &op);
if (op == 'Q') {
int l;
scanf("%d", &l);
t = getMax(r - l, r - 1); // 最後 L 個數是 r - l 到 r - 1,不是從 l 到 r
printf("%d\n", t);
} else {
int n;
scanf("%d", &n);
A[r] = (n + t) % D; // 要記錄 A[r]
change(r);
r++; // r 其實是作爲數列最右端的標識
}
}
return 0;
}
歡迎關注我的個人博客以閱讀更多優秀文章:凝神長老和他的朋友們(https://www.jxtxzzw.com)
也歡迎關注我的其他平臺:知乎( https://s.zzw.ink/zhihu )、知乎專欄( https://s.zzw.ink/zhuanlan )、嗶哩嗶哩( https://s.zzw.ink/blbl )、微信公衆號( 凝神長老和他的朋友們 )