2488. 树套树-简单版

题目链接

2488. 树套树-简单版

请你写出一种数据结构,来维护一个长度为 n 的序列,其中需要提供以下操作:

  1. 1 pos x,将 pos 位置的数修改为 x
  2. 2 l r x,查询整数 x 在区间 [l,r] 内的前驱(前驱定义为小于 x,且最大的数)。

数列中的位置从左到右依次标号为 1n

区间 [l,r] 表示从位置 l 到位置 r 之间(包括两端点)的所有数字。

区间内排名为 k 的值指区间内从小到大排在第 k 位的数值。(位次从 1 开始)

输入格式

第一行包含两个整数 n,m,表示数列长度以及操作次数。

第二行包含 n 个整数,表示有序数列。

接下来 m 行,每行包含一个操作指令,格式如题目所述。

输出格式

对于所有操作 2,每个操作输出一个查询结果,每个结果占一行。

数据范围

1n,m5×104,
1lrn,
1posn,
0x108,
有序数列中的数字始终满足在 [0,108] 范围内,
数据保证所有操作一定合法,所有查询一定有解。

输入样例:

5 3 3 4 2 1 5 2 2 4 4 1 3 5 2 2 4 4

输出样例:

2 1

解题思路

树套树,线段树套STL

树套树是一个思想,即内层树维护外层树的信息,常见的外层树有线段树/树状数组,内层树有平衡树(STL)/线段树,例如线段树套平衡树,线段树每个节点维护的是一个区间,而该区间的某些信息又由平衡树来维护

本题要求找到某个区间中小于 x 的最大数,可以由线段树找到组成该区间的 O(logn) 段的小区间,然后在每个小区间中找到小于 x 的最大数,每个小区间取最大值即可,可以用平衡树来查询每个小区间的信息,同时可用 multiset 来替代平衡树

  • 时间复杂度:O(nlog2n)

代码

// Problem: 树套树-简单版 // Contest: AcWing // URL: https://www.acwing.com/problem/content/description/2490/ // Memory Limit: 64 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #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__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16462737.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示