题目链接
请你写出一种数据结构,来维护一个长度为 n 的序列,其中需要提供以下操作:
1 pos x
,将 pos 位置的数修改为 x。
2 l r x
,查询整数 x 在区间 [l,r] 内的前驱(前驱定义为小于 x,且最大的数)。
数列中的位置从左到右依次标号为 1∼n。
区间 [l,r] 表示从位置 l 到位置 r 之间(包括两端点)的所有数字。
区间内排名为 k 的值指区间内从小到大排在第 k 位的数值。(位次从 1 开始)
输入格式
第一行包含两个整数 n,m,表示数列长度以及操作次数。
第二行包含 n 个整数,表示有序数列。
接下来 m 行,每行包含一个操作指令,格式如题目所述。
输出格式
对于所有操作 2,每个操作输出一个查询结果,每个结果占一行。
数据范围
1≤n,m≤5×104,
1≤l≤r≤n,
1≤pos≤n,
0≤x≤108,
有序数列中的数字始终满足在 [0,108] 范围内,
数据保证所有操作一定合法,所有查询一定有解。
输入样例:
输出样例:
解题思路
树套树,线段树套STL
树套树是一个思想,即内层树维护外层树的信息,常见的外层树有线段树/树状数组,内层树有平衡树(STL)/线段树,例如线段树套平衡树,线段树每个节点维护的是一个区间,而该区间的某些信息又由平衡树来维护
本题要求找到某个区间中小于 x 的最大数,可以由线段树找到组成该区间的 O(logn) 段的小区间,然后在每个小区间中找到小于 x 的最大数,每个小区间取最大值即可,可以用平衡树来查询每个小区间的信息,同时可用 multiset 来替代平衡树
代码
#include <bits/stdc++.h>
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=5e4+5,inf=1e9;
int n,m,w[N];
struct Tr
{
int l,r;
multiset<int> s;
}tr[4*N];
void build(int p,int l,int r)
{
tr[p].l=l,tr[p].r=r;
tr[p].s.insert(-inf),tr[p].s.insert(inf);
for(int i=l;i<=r;i++)tr[p].s.insert(w[i]);
if(l==r)return ;
int mid=l+r>>1;
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
}
void change(int p,int x,int y)
{
tr[p].s.erase(tr[p].s.lower_bound(w[x]));
tr[p].s.insert(y);
if(tr[p].l==tr[p].r)return ;
int mid=tr[p].l+tr[p].r>>1;
if(x<=mid)change(p<<1,x,y);
else
change(p<<1|1,x,y);
}
int ask(int p,int l,int r,int x)
{
if(l<=tr[p].l&&tr[p].r<=r)
{
auto it=tr[p].s.lower_bound(x);
return *(--it);
}
int res=-inf;
int mid=tr[p].l+tr[p].r>>1;
if(l<=mid)res=max(res,ask(p<<1,l,r,x));
if(r>mid)res=max(res,ask(p<<1|1,l,r,x));
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&w[i]);
build(1,1,n);
while(m--)
{
int op,pos,l,r,x;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&pos,&x);
change(1,pos,x);
w[pos]=x;
}
else
{
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",ask(1,l,r,x));
}
}
return 0;
}
__EOF__
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战