2488. 树套树-简单版

题目链接

2488. 树套树-简单版

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

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

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

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

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

输入格式

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

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

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

输出格式

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

数据范围

\(1 \le n,m \le 5 \times 10^4\),
\(1 \le l \le r \le n\),
\(1 \le pos \le n\),
\(0 \le x \le 10^8\),
有序数列中的数字始终满足在 \([0,10^8]\) 范围内,
数据保证所有操作一定合法,所有查询一定有解。

输入样例:

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(nlog^2n)\)

代码

// 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;
}
posted @ 2022-07-10 10:40  zyy2001  阅读(51)  评论(0编辑  收藏  举报