火星饭店
使用线段树处理,不能使用树状数组,因为树状数组管理的区域是固定的,就是 lowbit(i) 的长度,i 是树状数组的下标,而这道题的显示 L 个菜品的 L是灵活的,要是用树状数组来管理区间最大值显然太死了,不够灵活。
复习一下线段树的数据结构的可视化图:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll cai[10000000] = {0}; //线段树,维护菜的最大美味度,注意是按照更新时间逆序排的
void update(ll p, ll v, ll x, ll l, ll r) //在位置p新增加值v,这个时候遍历到x,其管理的区间是[l,r]
{
if (l == r)
{
cai[x] = v;//这里的x并不一定是p啊!这里的x是线段树数组管理原数组下标是p位置的地方
return;
}
ll m = (l + r) / 2;
if (p <= m)
update(p, v, x * 2, l, m);
else
update(p, v, x * 2 + 1, m + 1, r);
cai[x] = max(cai[x * 2], cai[x * 2 + 1]);//!注意要先更新子节点,才可以更新当前这个节点
}
ll chaxun(ll p1, ll p2, ll x, ll l, ll r) //查询p1到p2之间最大的菜品美味度
{
if (l == p1 && r == p2)
return cai[x];
ll m = (l + r) / 2;
if (p2 <= m)
return chaxun(p1, p2, x * 2, l, m);
else if (p1 > m)
return chaxun(p1, p2, x * 2 + 1, m + 1, r);
return max(chaxun(p1, m, x * 2, l, m), chaxun(m + 1, p2, x * 2 + 1, m + 1, r));
}
int main()
{
ll m, p;
cin >> m >> p;
ll pre = 0; //记录上一个点的菜
ll zhong = 0; //记录有几个菜
for (ll i = 0; i < m; i++)
{
char choice;
cin >> choice;
if (choice == 'A')
{
ll t;
scanf("%lld",&t);
ll meiweidu = (t + pre) % p;
zhong++;
//更新线段树
update(zhong,meiweidu,1,1,m);//!注意这里要直接维护到最大的长度,不要去等他扩展,因为有可能随着数组中元素的增加,一些点的覆盖范围就和原来不一样了
}
else
{
ll l;
cin >> l;
pre = chaxun(zhong - l + 1,zhong,1,1,m);
cout << pre << endl;
}
}
return 0;
}