洛谷P1198:最大值 ← 线段树

【问题来源】
https://www.luogu.com.cn/problem/P1198
https://www.acwing.com/problem/content/description/1277/

【问题描述】
现在请求你维护一个数列,要求提供以下两种操作:
1. 查询操作。
语法:Q L
功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。
限制:L不超过当前数列的长度。(L>0)
2. 插入操作。
语法:A n
功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。
限制:n是整数(可能为负数)并且在长整范围内。
注意:初始时数列是空的,没有一个数。

【输入格式】
第一行两个整数,M 和 D,其中 M 表示操作的个数,D 如上文中所述。
接下来的 M 行,每行一个字符串,描述一个具体的操作。语法如上文所述。

【输出格式】
对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。

【输入输出样例】
输入:
5 100
A 96
Q 1
A 97
Q 1
Q 2

输出:
96
93
96

【数据规模与约定】
对于全部的测试点,保证 1≤M≤2×10^5,1≤D≤2×10^9。

【算法代码】

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int maxn=200005;
const int inf=0x3f3f3f3f;
int a[maxn];

struct node {
    int le,ri,mx;
} tree[maxn*4];

void build(int k,int le,int ri) {
    tree[k].le=le;
    tree[k].ri=ri;
    if(le==ri) {
        tree[k].mx=a[le];
        return;
    }
    int mid,lson,rson;
    mid=(le+ri)/2;
    lson=k*2;
    rson=k*2+1;
    build(lson,le,mid);
    build(rson,mid+1,ri);
    tree[k].mx=max(tree[lson].mx,tree[rson].mx);
}

void update(int k,int i,int v) { //点更新
    if(tree[k].le==tree[k].ri && tree[k].le==i) {
        tree[k].mx=v;
        return;
    }
    int mid,lson,rson;
    mid=(tree[k].le+tree[k].ri)/2;
    lson=k*2;
    rson=k*2+1;
    if(i<=mid) update(lson,i,v);
    else update(rson,i,v);
    tree[k].mx=max(tree[lson].mx,tree[rson].mx);
}

int query(int k,int le,int ri) { //区间查询
    if(tree[k].le>=le && tree[k].ri<=ri)
        return tree[k].mx;
    int mid,lson,rson;
    mid=(tree[k].le+tree[k].ri)/2;
    lson=k*2;
    rson=k*2+1;
    int iMAX=-inf;
    if(le<=mid)
        iMAX=max(iMAX,query(lson,le,ri));
    if(ri>mid)
        iMAX=max(iMAX,query(rson,le,ri));
    return iMAX;
}

int main() {
    int n=0, last=0; //n为结点个数,last为上一次查询结果
    int M,D; //M为操作次数
    cin>>M>>D;
    build(1, 1, M);

    while(M--) {
        char op;
        cin>>op;
        if(op=='A') {
            LL t;
            cin>>t;
            update(1, n+1, (t+last)%D); //在n+1处插入结点
            n++; //结点个数+1
        } else {
            int L;
            cin>>L;
            last=query(1,n-L+1,n); //查询[n-L+1, n]内的最大值,k=1表示从根节点开始查询
            cout<<last<<endl;
        }
    }

    return 0;
}




/*
in:
10 100
A 97
Q 1
Q 1
A 17
Q 2
A 63
Q 1
Q 1
Q 3
A 99

out:
97
97
97
60
60
97
*/



【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/120590584
https://www.luogu.com.cn/problem/P1198
https://www.acwing.com/problem/content/description/1277/

Guess you like

Origin blog.csdn.net/hnjzsyjyj/article/details/120595514