FHVirus' 隨筆

pb_ds tree

2021-02-07

因為寫題會用到就順便寫一篇吧。

什麼是平板電視樹(pb_ds tree)?

黑魔法。

它可以幹嘛?

大致上,平板電視樹可以當作 std::setstd::map 使用(以下以當作 std::set 用為主),但同時又支援兩種實作很麻煩的操作:

怎麼用?

宣告

首先是標頭檔:

1
2
#include<bits/extc++.h>
using namespace __gnu_pbds;

再來是型別宣告:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update>;
// 好長對吧?分開來看看
tree<
  int,				// 資料型別
	null_type,	// 當作 map 使用的時候要對應什麼資料型態,
							// 要當作 set 就用 null_type
	less<int>,	// key value 要用什麼方式比較
							// 類似 priority_queue 的用法
	rb_tree_tag,// 這顆 tree 要用哪種結構
							// 大多時候會用紅黑樹(rb_tree)
	tree_order_statistics_node_update
    					// 神秘的黑魔法,待補
>;

使用

直接看模板題的扣的吧。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Knapsack DP is harder than FFT.
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
typedef int64_t ll;
template<typename T> using rbt = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
int32_t main(){
	ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int n;
	rbt<ll> eek;
	cin >> n;
	for(ll opt, x; n; --n){
		cin >> opt >> x;
		if(opt == 1) eek.insert((x<<20) + n);
		else if(opt == 2) eek.erase(eek.lower_bound(x<<20));
		else if(opt == 3) cout << eek.order_of_key(x<<20) + 1 << '\n';
		else if(opt == 4) cout << (*eek.find_by_order(x-1) >> 20) << '\n';
		else if(opt == 5) cout << (*--eek.lower_bound(x<<20) >> 20) << '\n';
		else if(opt == 6) cout << (*eek.lower_bound((x+1)<<20) >> 20) << '\n';
	}
	return 0;
}

參考資料