P6136 【模板】普通平衡树(数据加强版)题解 pb_ds 模版

【模板】普通平衡树(数据加强版)

传送门

题目背景

本题是 P3369 数据加强版,扩大数据范围并增加了强制在线

题目的输入、输出和原题略有不同,但需要支持的操作相同。

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些整数,其中需要提供以下操作:

  1. 插入一个整数 x x x
  2. 删除一个整数 x x x(若有多个相同的数,只删除一个)。
  3. 查询整数 x x x 的排名(排名定义为比当前数小的数的个数 + 1 +1 +1)。
  4. 查询排名为 x x x 的数(如果不存在,则认为是排名小于 x x x 的最大数。保证 x x x 不会超过当前数据结构中数的总数)。
  5. x x x 的前驱(前驱定义为小于 x x x,且最大的数)。
  6. x x x 的后继(后继定义为大于 x x x,且最小的数)。

本题强制在线,保证所有操作合法(操作 2 2 2 保证存在至少一个 x x x,操作 4 , 5 , 6 4,5,6 4,5,6 保证存在答案)。

输入格式

第一行两个正整数 n , m n,m n,m,表示初始数的个数和操作的个数。

第二行 n n n 个整数 a 1 , a 2 , a 3 , … , a n a_1,a_2,a_3,\ldots,a_n a1,a2,a3,,an,表示初始的数

接下来 m m m 行,每行有两个整数 opt \text{opt} opt x ′ x' x opt \text{opt} opt 表示操作的序号($ 1 \leq \text{opt} \leq 6 ), ), ),x’$ 表示加密后的操作数。

我们记 last \text{last} last 表示上一次 3 , 4 , 5 , 6 3,4,5,6 3,4,5,6 操作的答案,则每次操作的 x ′ x' x 都要异或 last \text{last} last 才是真实的 x x x。初始 last \text{last} last 0 0 0

输出格式

输出一行一个整数,表示所有 3 , 4 , 5 , 6 3,4,5,6 3,4,5,6 操作的答案的异或和

样例 #1

样例输入 #1

6 7
1 1 4 5 1 4
2 1
1 9
4 1
5 8
3 13
6 7
1 4

样例输出 #1

6

提示

样例解释

样例加密前为:

6 7
1 1 4 5 1 4
2 1
1 9
4 1
5 9
3 8
6 1
1 0

限制与约定

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 5 1\leq n\leq 10^5 1n105 1 ≤ m ≤ 1 0 6 1\leq m\leq 10^6 1m106 0 ≤ a i , x < 2 30 0\leq a_i,x\lt 2^{30} 0ai,x<230

本题输入数据较大,请使用较快的读入方式。


upd 2022.7.22 \text{upd 2022.7.22} upd 2022.7.22:新增加 9 9 9 组 Hack 数据。

注明

以上来自洛谷。 以上来自洛谷。 以上来自洛谷。
有 pb_ds 做法但是不能交题解,太/oh了。

解题思路

前置知识

正文

提供一种 pb_ds 做法,代码非常短。

因为是平衡树模版,直接使用 pb_ds 即可。注意在输入 x ′ x^{'} x要异或上上一次 3 , 4 , 5 , 6 3,4,5,6 3,4,5,6 操作的答案;最终答案为所有 3 , 4 , 5 , 6 3,4,5,6 3,4,5,6 操作的答案的异或和tree 一定!一定!要开 unsigned long longlong long 左移 20 20 20 位可能会爆。

说完注意点,接下来只有用 pb_ds 库中内置的平衡树实现题目中的相应操作即可。

AC Code

#include<bits/stdc++.h>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
#define int unsigned long long
int n, m, a[100005];
tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> Tree;
int Answer;
signed main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0), cin >> n >> m;
	for (register int i = 1; i <= n; ++i) cin >> a[i], Tree.insert((a[i] << 20) + i);
	short opt;
	int x, last = 0;
	for (register int i = 1; i <= m; ++i) {
		cin >> opt >> x, x ^= last;
		if (opt == 1) Tree.insert((x << 20) + i);
		else if (opt == 2) Tree.erase(Tree.lower_bound(x << 20));
		else if (opt == 3) last = Tree.order_of_key(x << 20) + 1, Answer ^= last;
		else {
			if (opt == 4) last = *Tree.find_by_order(x - 1);
			if (opt == 5) last = *--Tree.lower_bound(x << 20);
			if (opt == 6) last = *Tree.lower_bound((x + 1) << 20);
			last >>= 20, Answer ^= last;
		}
	}
	cout << Answer << endl;
	return 0;
}

想想看赛场上其他人调一万年平衡树没调出来但是你用 pb_ds 10 m i n 10min 10min 通过的快感。

  • 20
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值