题目链接:[JSOI2008] 最大数 - 洛谷
PS:本题解使用的是线段树解法。我们通读整个题目。
首先先说为什么要用线段树。我们可以看出来数组长度的最大值是2e5,并且每次查询的最坏的情况是O(N)的时间复杂度,这样一计算,发现最坏的情况是2e10,远大于1e8,必定TLE,所以使用查询复杂度为log(N)的线段树。假设每次查询的时候都是最坏的情况log(2e5)约等于17,这样时间复杂度降到了O(N)*10,完毕,不会TLE。
然后再说这题该怎么用线段树去写
首先我们得知道我们线段树维护的是什么,那么这题显而易见嘛,是区间的max值(后面我们的max值用mx代替,只有使用max函数的时候会使用max)
其次我们看题目中的操作。我们先看插入的操作,因为题目中说了初始时数列是空的,没有一个数。那么我们建树的时候可以让所有的节点变成0,包括线段树的叶子节点,这样每次插入的时候,相当于就是我们只要修改线段树的每一个叶子节点就行了,然后在pushup更新上面的节点就行了。
放出宏定义
#define int long long
#define lc u<<1//左孩子节点
#define rc u<<1|1//右孩子节点
const int N = 200010;
const int INF = -0x3f3f3f3f;//无穷小
放出Tree
struct Tree
{
int l;
int r;
int mx;//维护的最大值
}tr[4*N];
先放出pushup的代码
我觉得pushup函数应该不需要过多的解释了吧,但是我这里还是解释一下好
父节点的mx值肯定是根据这个父节点的两个子节点来更新的,父节点的区间是两个孩子区间的合并,所以父节点的大区间的mx值肯定是取两个孩子区间的mx值嘛。
void pushup(int u)//u是父节点
{
tr[u].mx = max(tr[lc].mx,tr[rc].mx);//向上更新mx值
}
这里放出建树的代码
void build(int u,int l,int r)//u是父节点
{
tr[u]={l,r,0};//每一个节点都初始化为0
if(l == r) return;//找到叶子节点
int m = l+r>>1;//分裂
build(lc,l,m);
build(rc,m+1,r);
}
这里放出插入的代码(其实就是单点修改的代码)
void change(int u,int x,int v)
{
if(tr[u].l == x && tr[u].r == x)//找到目标点位
{
tr[u].mx = v;
return;
}
int m = tr[u].l+tr[u].r>>1;
if(x<=m) change(lc,x,v);//如果小了,则找左子树
if(x>m) change(rc,x,v);//大了就找右子树
pushup(u);//最后修改完更新
}
然后就是查询的操作
这里放出查询的代码
int query(int u,int l,int r)
{
if(l<=tr[u].l && tr[u].r<=r) return tr[u].mx;//如果查找的区间完全覆盖tr[u]的两边则直接return这个区间的mx值
int m = tr[u].l+tr[u].r>>1;//否则就分裂
int res = INF;//为了找出最大值
if(l<=m) res = query(lc,l,r);
if(r>m) res = max(res,query(rc,l,r));
return res;
}
我们还要把查询的结果存起来,因为插入的时候需要用到上一次查询的结果嘛
这里我们放出solve()函数
void solve()
{
cin>>m>>p;//p是模的数
build(1,1,m);//建树,最多m个叶子节点
char op;int x;
int n = 0,t = 0;
while(m--)
{
cin>>op>>x;
if(op == 'A') change(1,++n,(x+t)%p);//++n是为了方便的插入第一个第二个一直到第n个数
else
{
t = query(1,n-x+1,n);//存起来查询的结果
cout<<t<<endl;
}
}
}
还有不理解的可以把你的疑问放在评论区,不要忘记点赞+关注哟!!!
最后放出完整代码
#include <bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
#define lc u<<1
#define rc u<<1|1
const int N = 200010;
const int INF = -0x3f3f3f3f;
typedef long long LL;
int m,p;
struct Tree
{
int l;
int r;
int mx;
}tr[4*N];
void pushup(int u)
{
tr[u].mx = max(tr[lc].mx,tr[rc].mx);
}
void build(int u,int l,int r)
{
tr[u]={l,r,0};
if(l == r) return;
int m = l+r>>1;
build(lc,l,m);
build(rc,m+1,r);
}
void change(int u,int x,int v)
{
if(tr[u].l == x && tr[u].r == x)
{
tr[u].mx = v;
return;
}
int m = tr[u].l+tr[u].r>>1;
if(x<=m) change(lc,x,v);
if(x>m) change(rc,x,v);
pushup(u);
}
int query(int u,int l,int r)
{
if(l<=tr[u].l && tr[u].r<=r) return tr[u].mx;
int m = tr[u].l+tr[u].r>>1;
int res = INF;
if(l<=m) res = query(lc,l,r);
if(r>m) res = max(res,query(rc,l,r));
return res;
}
void solve()
{
cin>>m>>p;
build(1,1,m);
char op;int x;
int n = 0,t = 0;
while(m--)
{
cin>>op>>x;
if(op == 'A') change(1,++n,(x+t)%p);
else
{
t = query(1,n-x+1,n);
cout<<t<<endl;
}
}
}
signed main()
{
solve();
}