# 110 選手班 - 基礎資結
###### tags: `宜中資訊` `CP`
Ccucumber12
2020.08.06
---
## Outline
- Binary heap
- DSU
- Sparse table
- Fenwick tree
- Segment tree
---
## Binary Heap
----
### Function
- Insert
- Query Max/Min
- Pop Max/Min
----
### Structure
- Complete binary tree
- Father $\geq$ Child
- Root is max/min
- Array implement
----
![](https://i.imgur.com/ubll24I.png)
----
### Insert
- insert at the lowest leaf
- adjust upwards
- $O(log\ N)$
----
### Pop
- swap root and lowest leaf
- delete lowest leaf
- adjust downwards
- $O(log\ N)$
----
### Implementation
```c=
const int INF = 0x3f3f3f3f ;
int hp[2000010] ;
int e = 0 ;
void init() {
for(int i=1; i<=100000; ++i)
hp[i] = -INF ;
}
void insert(int x) {
e++ ;
hp[e] = x ;
int tmp = e ;
// current index
while(tmp > 1 && hp[tmp] > hp[tmp / 2]) {
swap(hp[tmp], hp[tmp/2]) ;
tmp /= 2 ;
}
}
void pop() {
swap(hp[1], hp[e]) ;
hp[e] = -INF ;
e-- ;
int tmp = 1 ;
while(hp[tmp] < max(hp[tmp * 2], hp[tmp * 2 + 1])) {
int l = tmp * 2, r = tmp * 2 + 1 ;
if(hp[l] > hp[r]) {
swap(hp[tmp], hp[l]) ;
tmp = l ;
} else {
swap(hp[tmp], hp[r]) ;
tmp = r ;
}
}
}
```
---
## Disjoint Set Union
----
### Function
- query set's index
- query if same set
- unite two sets
----
### Structure
- Tree / Forest
- father is itself: root
- set index: root
- Array Implement
----
![](https://i.imgur.com/PBDC51e.png)
----
### Initialize
- Every index is independent
- Let every index point to themselves
- $O(N)$
----
### Find
- Find the root of current index
- Recursive until root
- Shorten the path
- $O(\alpha(N))$
----
### Unite
- Combine two sets
- Let one root's father := the other root
- Modify the smaller group
- $O(\alpha(N))$
----
### Query
- query if two index is same set
- use find()
- $O(\alpha(N))$
----
### Implementation
```c=
int dsu[100010] ;
void init() {
for(int i=0; i<=100000; ++i)
dsu[i] = i ;
}
int find(int x) {
return dsu[x] == x ? x : dsu[x] = find(dsu[x]) ;
}
void unite(int x, int y) {
dsu[find(y)] = find(x) ;
}
```
---
## Sparse Table
----
### Function
- Static RMQ
- O(1) Query
----
### RMQ
- Range Minimum/Maximum Query
- Sum, Multiplication, GCD, XOR, ...
- Static / Dynamic
----
### Structure
- $(N) \times (log\ N)$ table
- $spt[i][j]\ :=\ min[i,\ i + 2^j-1]$
----
![](https://i.imgur.com/Mu9tJ0d.png)
----
### Build
- $spt[i][j]\ :=\ min[i,\ i + 2^j - 1]$
- $spt[i][0] = a[i]$
- $spt[i][j+1] = min(spt[i][j],\ spt[i+2^j][j])$
----
- DP
- $O(Nlog\ N)$
----
### Query
- $lg\ :=\ log\lfloor r-l+1\rfloor$
- query(l, r) = $min(spt[l][lg], spt[r - 2^{lg}+1][lg])$
- $O(1)$
----
### Implementation
```c=
int a[100010] ;
int spt[200010][30] ;
void build(int n) {
for(int i=1; i<=n; ++i) {
spt[i][0] = a[i] ;
}
for(int i=1; i<=log2(n); ++i) {
for(int j=1; j<=n; ++j) {
spt[j][i] = max(spt[j][i-1], spt[j + (1 << (i-1))][i-1]) ;
}
}
}
int query(int l, int r) {
int lg = log2(r - l + 1) ;
return min(spt[l][lg], spt[r - (1<<lg) + 1][lg]) ;
}
```
----
### KEY
- +1 / -1
- query minimum $\rightarrow$ initialize
- boudaries (RE)
---
## Fenwick Tree
----
### Names
- Fenwick Tree
- Binary Indexed Tree
- 樹狀陣列
- 二元索引樹
- BIT
----
### Function
- Range Sum Query
- add value
----
### Structure
- (Half) Perfect Binary Tree
- $bt[i] = sum[i - lowbit(i) + 1,\ i]$
----
### Lowbit
- LSB(Least Significant Bit)
- $12 = 1100_{(2)} \rightarrow lowbit(12) = 100_{(2)} = 4$
- $8 = 1000_{(2)} \rightarrow lowbit(8) = 1000_{(2)} = 8$
----
- `lowbit(x) = (x&-x)`
- $12 = ...001100_{(2)}$
- $-12 = ...110100_{(2)}$
- $12\ \&-12 = ...000100_{(2)}$
----
![](https://i.imgur.com/Ga0wPIz.png)
----
![](https://i.imgur.com/klc0CIX.png)
----
### Add
- add $k$ to index $x$
- modify every range include $x$
- enumerate through adding lowbit
- $O(log\ N)$
----
### Query
- Query $sum[1, x]$
- add different ranges to sum up $[1,x]$
- enumerate through subtracting lowbig
- $O(log\ N)$
----
### Implementation
```c=
int bt[100010] ;
int n ;
void add(int x, int k) {
for(int i=x; i<=n; i += (i&-i)) {
bt[i] += k ;
}
}
void add(int x, int y, int k) {
for(int i=x; i<=n; i+=(i&-i))
for(int j=y; j<=n; j+=(i&-j))
bt[i][j] = k ;
}
int query(int x) {
int ret = 0 ;
for(int i=x; i>0; i -= (i&-i)) {
ret += bt[i] ;
}
return ret ;
}
int sum(int l, int r) {
return query(r) - query(l - 1) ;
}
```
----
### Advance
- XOR
- monotonic Max / Min
- 2D BIT
---
## Segment Tree
----
### Function
- Range Min/Max/Sum Query
- Modify value
----
### Structure
- Perfect Binary Tree
- combine adjacent ranges every new layer
- $O(N) \times O(log\ N)$ size
----
![](https://i.imgur.com/OS9uzUQ.png)
----
### Build
- make length into power of two
- recursive
- $[L, R] = f([L,mid],\ [mid+1,R])$
- $O(N)$
----
### Modify
- modify index $x$ to $k$
- adjust every ancestor of $x$
- going up by dividing two
- $O(log\ N)$
----
### Query
- Query $f[l, r]$
- start from $[1,N]$
- recursive $[Lb, Rb] = f([Lb, mid],\ [mid+1,Rb])$
- $O(log\ N)$
----
### Implementation
```c=
int N, MXN ;
int seg[4000010] ; // 4 * N
void build(int lb, int rb, int idx) {
if(lb == rb) return ;
int mid = (lb + rb) / 2 ;
build(lb, mid, idx*2) ;
build(mid + 1, rb, idx*2+1) ;
seg[idx] = seg[idx*2] + seg[idx*2+1] ;
}
void modify(int x, int k) {
x = x + MXN - 1 ;
seg[x] = k ;
while(x > 1) {
x /= 2 ;
seg[x] = seg[x*2] + seg[x*2+1] ;
}
}
int query(int l, int r, int lb, int rb, int idx) {
if(l <= lb && rb <= r) {
return seg[idx] ;
}
int mid = (lb + rb) / 2 ;
int ret = 0 ;
if(l <= mid) ret += query(l, r, lb, mid, idx*2) ;
if(r >= mid+1) ret += query(l, r, mid+1, rb, idx*2+1) ;
return ret ;
}
int main() {
int a[100010] ;
cin >> N ;
MXN = 1 ;
while(MXN < N)
MXN <<= 1 ;
for(int i=1; i<=N; ++i)
seg[MXN + i - 1] = a[i] ;
build(1, MXN, 1) ;
}
```
----
### Advance
- Lazy Tag
- Range Modify
- GCD, XOR
- D&Q
---
## Credit
- https://helloacm.com/disjoint-sets/
- https://hackmd.io/@Lssh-Algorithm/S1fUmuUJ_
- https://www.youtube.com/watch?v=uUatD9AudXo
- Sprout
- OI wiki
{"metaMigratedAt":"2023-06-16T05:48:43.760Z","metaMigratedFrom":"Content","title":"110 選手班 - 基礎資結","breaks":true,"contributors":"[{\"id\":\"45262441-89e4-46ca-959b-c0d6fadb64e2\",\"add\":6449,\"del\":44}]"}