計蒜客 - 蒜頭君的任務

計蒜客 蒜頭君的任務

題目描述

蒜頭君的上司給蒜頭君佈置了一個任務,蒜頭君維護一個數列,要求提供以下兩種操作:

  1. 查詢操作。

語法:Q L

功能:查詢當前數列中末尾 LL 個數中的最大的數,並輸出這個數的值。

  1. 插入操作。

語法:A n

功能:將 nn 加上 tt,其中 tt 是最近一次查詢操作的答案(如果還未執行過查詢操作,則 t=0t = 0),並將所得結果對一個固定的常數 DD 取模,將所得答案插入到數列的末尾。

初始時數列是空的,沒有一個數。

樣例

樣例輸入

第一行兩個整數,MMDD,其中 MM 表示操作的個數(M200000M \leq 200000),DD 如上文中所述,滿足 DD3232 位整型範圍內。

接下來 MM 行,查詢操作或者插入操作。

5 100
A 96
Q 1
A 97
Q 1
Q 2

樣例輸出

對於每一個詢問操作,輸出一行。該行只有一個數,即序列中最後 LL 個數的最大數。

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 )、微信公衆號( 凝神長老和他的朋友們 )
凝神長老的二維碼們

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章