---
# System prepended metadata

title: RMQ 問題
tags: [經典問題]

---

###### tags: `經典問題`

# RMQ 問題
## 問題敘述
對於一個長度為 $n$ 的 array，可以實行以下兩種操作。
* $update(x, y)$:
    將 array 的第 $x$ 個元素值更新成 $y$。
* $query(l, r)$:
    詢問 array 在 $[l, r]$ 這個範圍內的最大值或最小值是多少。

## Segment Tree
線段樹應該是拿來做 RMQ 問題的常用手段了，build 的時間複雜度 $O(n*logn)$，update 與 query 的時間複雜度都是 $O(log(n))$。

要注意線段樹需要 $4n$ 的空間來儲存。
```c++=
vector<int> tree;
// l, r, idx是線段樹的內部變數
int build(int l, int r, int idx, vector<int> &arr){ // 沒有測試過，但大概的code應該是長這樣
    if(l == r)
        return tree[idx] = arr[l];
    int mid = (l+r)/2;
    int l_result = build(l, mid, idx*2+1, arr);
    int r_result = build(mid+1, r, idx*2+2, arr);
    return tree[idx] = max(l_result, r_result);
}
int update(int l, int r, int idx, int x, int y){ // 將arr[x]改成y
    if(l == r)
        return tree[idx] = y;

    int mid = (l+r)/2;
    if(x<=mid)
        return tree[idx] = max(update(l, mid, idx*2+1, x, y), tree[idx*2+2]);
    else return tree[idx] = max(tree[idx*2+1], update(mid+1, r, idx*2+2, x, y));
}
int query(int l, int r, int L, int R, int idx){ // 找[L, R]中的最大值
    if(L == l && R == r)
        return tree[idx];
    int mid = (l+r)/2;

    if(R<=mid)
        return query(l, mid, L, R, idx*2+1);
    else if(L>mid)
        return query(mid+1, r, L, R, idx*2+2);
    else {
        return max(query(l, mid, L, mid, idx*2+1), query(mid+1, r, mid+1, R, idx*2+2));
    }
}
```
## Binary Indexed Tree (Fenwick Tree)
根據[這篇](https://hackmd.io/@wiwiho/cp-note/%2F%40wiwiho%2FCPN-binary-indexed-tree)提到的想法，如果要用 BIT 解決 RMQ 問題，那 update 值的時候，如果要做最大值，那值就只能被改大，做最小值，那值就只能被改小。

這個方法 update 與 query 的時間複雜度應該都是 $O(log(n))$。

要注意 BIT 需要 $n$ 的空間來儲存。

```c++=
vector<int> BIT, arr; // 1-indexed
// 只能將值改大，不可改小
void update(int idx, int val){ // update arr[idx] = val
    arr[idx] = val;
    for(int i=idx;i<BIT.size();i+=i&-i)
        BIT[i] = max(BIT[i], val);
}
int query(int l, int r){ // query [l, r] 之間的最大值
    int ans = -1;
    for(int i=r;i>=l;){
        if(i - (i&-i) < l){
            ans = max(ans, arr[i]);
            i--;
        }
        else {
            ans = max(ans, BIT[i]);
            i-=i&-i;
        }
    }
    return ans;
}
```