# 區間和、最大值、最小值問題 --- # 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; } ```