---
# System prepended metadata

title: 區間和、最大值、最小值問題

---

# 區間和、最大值、最小值問題
---
# binary indexed tree 二叉樹
[https://zerojudge.tw/ShowProblem?problemid=f315](https://) -Apcs第4題

```cpp=
#include <bits/stdc++.h>
using namespace std;
#define SIZE 200005

long long ans = 0;
long long bit[SIZE];
int n;
int R[SIZE];
int L[SIZE];

int sum(int pos) {
    int s = 0;
    while(pos > 0) {
        s += bit[pos];
        pos -= pos & (-pos);
    }
    return s;
}

void add(int pos) {
    while(pos <= 2*n) {
        bit[pos] += 1;
        pos += pos & (-pos);
    }
}

int main () {
    cin >> n;
    for(int i = 1; i <= 2*n; i++) {
        int tmp;
        cin >> tmp;
        if(L[tmp] == 0) {
            L[tmp] = i;
        } else {
            R[tmp] = i;
        }
    }
    for(int i = 1; i <= n; i++) {
        ans += sum(R[i]) - sum(L[i]); /// sum
        add(R[i]);  add(L[i]); ///  setup binary tree
    }
    cout << ans;
}
```
## 1. 求左右兩邊大於中間的數
## 2. 從一開始，邊建表邊算ans

---
# segment tree 線段數
[https://zerojudge.tw/ShowProblem?problemid=d799](https://)
---
```cpp=
#include <bits/stdc++.h>
using namespace std;
#define AC ios_base::sync_with_stdio(0);  cin.tie(0);  cout.tie(0);
#define SIZE 1000005

int n;
int num[SIZE];
struct aka{
    long long sum;
    long long lazy;
}tree[SIZE];

int Lc(int n) {return n*2;}
int Rc(int n) {return n*2+1;}

void build(int x, int y, int k) {
    if (x == y) {
         tree[k].sum = num[x];
         tree[k].lazy = 0;
         return;
    }
    int m = (x+y)/2;
    build(x,m,Lc(k));
    build(m+1,y,Rc(k));
    tree[k].lazy = 0;
    tree[k].sum = tree[Lc(k)].sum + tree[Rc(k)].sum;
}

/**position  room  value**/
void update(int x, int y, int a, int b, int k, int val) {
    /**need to be updated**/
    if (tree[k].lazy != 0) {
        tree[k].sum += tree[k].lazy*(y-x+1);
        if (x != y) {
            tree[Rc(k)].lazy += tree[k].lazy;
            tree[Lc(k)].lazy += tree[k].lazy;
        }
        tree[k].lazy = 0;
    }
    if (x > b || y < a) return;
    if (x >= a && y <= b) {
        /**in the range change the sum then mark the child node**/
        tree[k].sum += val*(y-x+1);
        if (x != y) {
            tree[Lc(k)].lazy += val;
            tree[Rc(k)].lazy += val;
        }
        /**had been written**/
        return;
    }
    int m = (x+y)/2;
    update( x ,m,a,b,Lc(k),val);
    update(m+1,y,a,b,Rc(k),val);
    /**important!! the node need to be update at the end**/
    tree[k].sum = tree[Lc(k)].sum + tree[Rc(k)].sum;
}

long long query(int x, int y, int a, int b, int k) {
    if (tree[k].lazy != 0) {
        tree[k].sum += tree[k].lazy*(y-x+1);
        if (x != y) { /*propagation*/
            tree[Lc(k)].lazy += tree[k].lazy;
            tree[Rc(k)].lazy += tree[k].lazy;
        }
        /*init*/
        tree[k].lazy = 0;
    }
    if (x > b || y < a || x > y) return 0;
    /**return the sum**/
    if (x >= a && y <= b) return tree[k].sum;
    /**else go recursive**/
    int m = (x+y)/2;
    return query(x,m,a,b,Lc(k)) + query(m+1,y,a,b,Rc(k));
}

int main () {
    AC
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> num[i];
    }
    build(1,n,1);
    int m;
    cin >> m;
    while (m--) {
        int tmp, x, y, s;
        cin >> tmp;
        if (tmp == 1) {
            cin >> x >> y >> s;
            update(1,n,x,y,1,s);
            /*
            for (int i = n-1+x; i <= n-1+y; i++) cout << tree[i].lazy << " ";
            cout << endl;
            */
        } else if (tmp == 2) {
            cin >> x >> y;
            cout << query(1,n,x,y,1) << endl;
        }
    }

}



```

# 區間最小值 apcs zj g277 3.幸運數字
```cpp=
#include <bits/stdc++.h>
using namespace std;
#define AC ios_base::sync_with_stdio(0); cout.tie(0);
#define SIZE 300000

struct T{
    int minn;
    int m_pos;
};

T s[SIZE<<2], small = {INT_MAX,0};
int num[SIZE], n;
long long pre[SIZE];

void build(int L, int R, int k) {
    if(L == R) {
        s[k] = {num[L],L};
        return;
    }
    int m = (L+R)>>1;
    build(L,m,(k<<1));
    build(m+1,R,(k<<1)+1);
    s[k].minn = min(s[(k<<1)].minn,s[(k<<1)+1].minn);
    if(s[(k<<1)].minn < s[(k<<1)+1].minn) s[k].m_pos = s[(k<<1)].m_pos;
    else s[k].m_pos = s[(k<<1)+1].m_pos;
}


void find_small(int x, int y,int left, int right, int k) {

    if(x >= left && y <= right) {
        if(small.minn > s[k].minn) small = s[k];
        return;
    }
    if(x > right || left > y) return;
    int m = (x+y)>>1;
    if(m >= right) return find_small(x,m,left,right,(k<<1));
    else if(m < left) return find_small(m+1,y,left,right,(k<<1)+1);
    else {
        find_small(x,m,left,right,(k<<1));
        find_small(m+1,y,left,right,(k<<1)+1);
    }
}

int main() {
    AC
    cin >> n;
    for(int i = 1; i <= n; i++) {
        cin >> num[i];
        pre[i] = pre[i-1]+num[i];
    }
    build(1,n,1);
    int left = 1, right = n;
    while(left < right) {
        small = {INT_MAX,0};
        find_small(1,n,left,right,1);
        long long sL = pre[small.m_pos-1]-pre[left-1];
        long long sR = pre[right] - pre[small.m_pos];
        if(sR >= sL) left = small.m_pos+1;
        else right = small.m_pos-1;

    }
    cout << num[left] << endl;
}

```