AcWing 1275. 最大数
作者:互联网
题意:
给两种操作。
添加操作:向序列后添加一个数,序列长度变成 \(n+1\);
询问操作:询问这个序列中最后 \(L\) 个数中最大的数是多少。
思路:线段树裸题,通过单点修改和回溯中的\(pushup\)维护区间最大值。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 200010;
int m; // m个操作
int p; //需要结果mod p
//线段树的结构体
struct Node {
int l, r;
int v; // 区间[l, r]中的最大值
} tr[N << 2]; //开4倍空间
void pushup(int u) { // 由子节点的信息,来计算父节点的信息
tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
}
//构建
void build(int u, int l, int r) {
tr[u] = {l, r}; //记录区间起始值,不要忘记yxc两次倒在这里的历史~
if (l == r) return; //递归出口,only one就需要返回了
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
//查询以u为根节点,区间[l, r]中的最大值
int query(int u, int l, int r) {
if (tr[u].l >= l && tr[u].r <= r) return tr[u].v; //包含左儿子与右儿子,那么直接返回我的结果
int mid = tr[u].l + tr[u].r >> 1;
int v = 0;
if (l <= mid) v = query(u << 1, l, r); //与左儿子有交,递归求解
if (r > mid) v = max(v, query(u << 1 | 1, l, r)); //与右儿子有交,再次递归
return v;
}
// u为结点编号,更新该结点的区间最大值
void modify(int u, int x, int v) {
if (tr[u].l == tr[u].r)
tr[u].v = v; //叶节点,递归出口
else {
int mid = tr[u].l + tr[u].r >> 1;
//分治处理左右子树, 寻找x所在的子树
if (x <= mid)
modify(u << 1, x, v);
else
modify(u << 1 | 1, x, v);
//回溯,拿子结点的信息更新父节点, 即pushup操作
tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
}
}
// n表示树中的结点个数, last保存上一次查询的结果
int n, last;
int main() {
cin >> m >> p;
//每次向序列后添加一个数,连添加带查询,共有m次操作,所以结点的区间最大不超过m
//初始化线段树, 结点的区间最多为[1, m]。
build(1, 1, m); //其实构建本质上就是:(1)标识有多少个点,(2)每个点描述的是哪个区间
int x;
char op;
while (m--) {
cin >> op >> x;
if (op == 'A') {
//对于n+1的位置进行修改,值=(最后一次的last查询值 + x )%p
modify(1, n + 1, ((LL)last + x) % p);
n++;
} else {
//查询[n - x + 1, n]内的最大值,u = 1:从根节点开始查询
last = query(1, n - x + 1, n);
printf("%d\n", last);
}
}
return 0;
}
标签:last,最大数,int,1275,查询,添加,区间,AcWing,op 来源: https://www.cnblogs.com/littlehb/p/16152232.html