2488. 树套树-简单版(线段树套multiset)

活动 - AcWing

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

  1. 1 pos x,将 pos 位置的数修改为 x。
  2. 2 l r x,查询整数 x 在区间 [ll,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] 范围内,
数据保证所有操作一定合法,所有查询一定有解。

输入样例:
5 3
3 4 2 1 5
2 2 4 4
1 3 5
2 2 4 4
输出样例:
2
1

解析: 

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <sstream>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stdio.h>
#include <tuple>
using namespace std;
/*
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
*/
typedef long long LL;
//#define int long long
#define ld long double
//#define INT __int128
const LL INF = 0x3f3f3f3f3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int inf = 0x3f3f3f3f;
const LL mod = 998244353;
const ld eps = 1e-12;
const int N = 5e4 + 10, M = 5e5 + 10;
int n, m;
int A[N];
struct TREE {
	multiset<int>s;
}tr[N<<2];
#define ls u<<1
#define rs u<<1|1
void build(int l, int r, int u) {
	tr[u].s.insert(-inf), tr[u].s.insert(inf);
	for (int i = l; i <= r; i++) {
		tr[u].s.insert(A[i]);
	}
	if (l == r)return;
	int mid = l + r >> 1;
	build(l, mid, ls), build(mid + 1, r, rs);
}
void modify(int l, int r, int u, int pos, int x) {
	//cout << "____________" << l << " " << r << endl;
	tr[u].s.erase(tr[u].s.find(A[pos]));
	tr[u].s.insert(x);
	//A[pos] = x;
	if (l == r)return;
	int mid = l + r >> 1;
	if (pos <= mid)modify(l, mid, ls, pos, x);
	if (pos > mid)modify(mid + 1, r, rs, pos, x);
}
int query(int l, int r, int u, int L, int R, int x) {
	//cout << "___________" << l << " " << r << endl;
	if (L <= l && r <= R) {
		auto ret = tr[u].s.lower_bound(x);
		ret--;
		//cout << "______________" << l << " " << r << " " << *ret << endl;
		return *ret;
	}
	int ret = -inf;
	int mid = l + r >> 1;
	if (L <= mid)ret = max(ret, query(l, mid, ls, L, R, x));
	if (R > mid)ret = max(ret, query(mid+1, r, rs, L, R, x));
	//cout << "________________" << l << " " << r << " " << ret << endl;
	return ret;
}
signed main() {
	cin >> n >> m;
	for(int i=1;i<=n;i++){
		cin >> A[i];
	}
	//A[0] = -inf, A[n + 1] = inf;
	build(1, n, 1);
	//n++;
	int op;
	while (m--) {
		cin >> op;
		if (op == 1) {
			int pos, x;
			cin >> pos >> x;
			modify(1, n, 1, pos, x);
			A[pos] = x;
		}
		else {
			int l, r, x;
			cin >> l >> r >> x;
			cout << query(1, n, 1, l, r, x) << endl;
		}
	}
	return 0;
}

/*


20 30
49 1 39 13 13 11 0 15 27 28 20 41 19 17 6 7 33 0 13 0
1 9 1
2 1 6 31
2 6 13 5
1 16 26
2 13 16 30
2 2 8 31
1 7 16
2 13 18 12
2 13 14 43
1 17 45
2 8 15 2
1 8 1
2 13 13 24
1 5 5
1 10 10
1 13 49
1 17 15
2 6 14 33
2 4 16 44
1 18 33
2 6 8 40
2 7 15 2
2 2 2 6
1 10 2
2 1 13 14
2 5 8 38
2 8 15 46
1 15 45
1 14 49
2 14 18 42
*/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值