---
# System prepended metadata

title: '第六章 :進階資結'

---

# 第六章 :進階資結

## 前言
請先確定自己可以很好的使用基礎資結的內容，否則會太毒瘤。
:::spoiler 裡面是平板電視，想看得再點開，應該不會教。
## gp_hash_table
使用方法跟`map`一模一樣。
e.g.
```cpp=
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
signed main() {
    gp_hash_table<int, int> cnt;
    cnt[1]=20, cnt[9191921]=1234;
    cout<<cnt[1]<<" "<<cnt[9191921]; //20 1234
}
```
但常數在理想情況比`map`好太多了，`map`是使用紅黑樹，每次操作的時間複雜度是 $(O\log n)$，而`gp_hash_table`則是透過 [hash 進行運算](https://ithelp.ithome.com.tw/articles/10208884)，在 hash 不碰撞的情況，時間複雜度是 $O(1)$
* [$\text{Codeforces}$上其他使用者所補充的時間差距](https://codeforces.com/blog/entry/60737)

![image](https://hackmd.io/_uploads/BJcYFKcLJg.png)

### 自訂hash
由於原本hash很容易被卡，所以可以自訂hash。
e.g.
```cpp=
const int RANDOM = chrono::high_resolution_clock::now().time_since_epoch().count();
struct chash {
    int operator()(int x) const { return x ^ RANDOM; }
};
gp_hash_table<int, int, chash> table;
```
## rb_tree_tag
參考 [$\text{Codeforces}$](https://codeforces.com/blog/entry/11080)。
更強大的`set`。
e.g.
```cpp=
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>ordered_set;
signed main() {
    ordered_set s;
    s.insert(1);
    s.insert(2);
    s.erase(1);
    s.insert(3);
    cout<<*s.lower_bound(1)<<'\n';
    cout<<*s.find_by_order(1)<<'\n';//第1個元素是誰(0-based)。
    cout<<s.order_of_key(4)<<'\n'; //有幾個元素比4小。
}
```
操作的時間複雜度為 $O(\log n)$。
## 補充
* [rope](https://hackmd.io/@Viecon-342524/SJ1C2BUE9) 偏毒瘤，小心食用。
:::
## 線段樹
### 區間查詢
> 有一個數列 $a_1, a_2,...,a_n$，要對陣列做兩種操作。
> 1. $\text{sum L R :}$ 計算 $a_L+a_{L+1}+...+a_R$。
> 2. $\text{add P V :}$ 把 $a_P+整數$ $V$。
> * 條件限制
> 
> $1 \le n, q \le 10^6$

本章要教的線段樹
線段樹有三個主要的部分以及兩個操作。
1. $\text{build}$
2. $\text{modify}$
3. $\text{query}$
4. $\text{pull}$
5. $\text{push}$

## 練習題目
[Josephus Problem II CSES](https://cses.fi/problemset/task/2163/)
[奇怪的老闆](https://judge.cchs.chc.edu.tw/ShowProblem?problemid=a041)