题解:AcWing 1275 最大数
【题目来源】
AcWing:1275. 最大数 - AcWing题库
【题目描述】
给定一个正整数数列\(a_1,a_2,...,a_n\), 每一个数都在\(0\sim p-1\)之间。可以对这列数进行两种操作:
1.添加操作:向序列后添加一个数,序列长度变成 \(n+1\);
2.询问操作:询问这个序列中最后 \(L\) 个数中最大的数是多少。
程序运行的最开始,整数序列为空。一共要对整数序列进行\(m\)次操作。
写一个程序,读入操作的序列,并输出询问操作的答案。
【输入】
第一行有两个正整数\(m,p\),意义如题目描述;接下来\(m\)行,每一行表示一个操作。
如果该行的内容是\(Q\ L\),则表示这个操作是询问序列中最后 \(L\) 个数的最大数是多少;
如果是\(A\ t\),则表示向序列后面加一个数,加入的数是\((t+a)\ mod\ p\)。其中, \(t\)是输入的参数,\(a\)是在这个添加操作之前最后一个询问操作的答案(如果之前没有询问操作,则a=0)。
第一个操作一定是添加操作。对于询问操作,\(L>0\)且不超过当前序列的长度。
【输出】
对于每一个询问操作,输出一行。该行只有一个数,即序列中最后 \(L\) 个数的最大数。
【输入样例】
5 100
A 96
Q 1
A 97
Q 1
Q 2
【输出样例】
96
93
96
【算法标签】
《AcWing 1275 最大数》 #线段树#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 200010; // 最大操作次数
int m, p; // m: 操作次数, p: 模数
// 线段树节点结构体
struct Node
{
int l, r; // 节点管理的区间[l, r]
int v; // 区间[l, r]中的最大值
} tree[N * 4]; // 线段树数组(开4倍空间)
/**
* 向上更新父节点信息
* 用左右孩子的最大值更新当前节点的最大值
* @param u 当前节点编号
*/
void pushup(int u)
{
tree[u].v = max(tree[u << 1].v, tree[u << 1 | 1].v);
}
/**
* 构建线段树
* @param u 当前节点编号
* @param l 当前节点管理的左边界
* @param r 当前节点管理的右边界
*/
void build(int u, int l, int r)
{
tree[u] = {l, r}; // 设置节点管理的区间
// 如果是叶子节点,直接返回
if (l == r)
return;
// 计算中点,递归构建左右子树
int mid = l + r >> 1;
build(u << 1, l, mid); // 构建左子树
build(u << 1 | 1, mid + 1, r); // 构建右子树
}
/**
* 区间查询:查询区间[L, R]的最大值
* @param u 当前节点编号
* @param L 查询区间的左边界
* @param R 查询区间的右边界
* @return 区间[L, R]的最大值
*/
int query(int u, int L, int R)
{
// 如果当前节点区间完全包含在查询区间内,直接返回节点值
if (tree[u].l >= L && tree[u].r <= R)
return tree[u].v;
int mid = tree[u].l + tree[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;
}
/**
* 单点修改:将位置x的值修改为v
* @param u 当前节点编号
* @param x 要修改的位置
* @param v 新的值
*/
void modify(int u, int x, int v)
{
// 找到叶子节点,直接修改
if (tree[u].l == x && tree[u].r == x)
{
tree[u].v = v;
}
else
{
int mid = tree[u].l + tree[u].r >> 1;
// 根据x的位置决定递归修改左子树还是右子树
if (x <= mid)
modify(u << 1, x, v);
else
modify(u << 1 | 1, x, v);
// 修改后更新父节点的值
pushup(u);
}
}
int main()
{
int n = 0; // 当前已插入的数据个数
int last = 0; // 上一次查询的结果
cin >> m >> p; // 输入操作次数和模数
// 构建线段树,初始管理区间为[1, m]
build(1, 1, m);
char op[2]; // 操作类型
int x; // 操作参数
// 处理每个操作
while (m--)
{
cin >> op >> x;
if (op[0] == 'Q') // 查询操作
{
// 查询最后x个数的最大值
last = query(1, n - x + 1, n);
cout << last << endl;
}
else // 插入操作('A')
{
// 在n+1位置插入新值:(last + x) % p
LL new_val = ((LL)last + x) % p;
modify(1, n + 1, new_val);
n++; // 数据个数加1
}
}
return 0;
}
【运行结果】
5 100
A 96
Q 1
96
A 97
Q 1
93
Q 2
96
浙公网安备 33010602011771号