演算法基礎課:離散化
阿新 • • 發佈:2022-05-24
離散化
特指整數離散化,有序、保序離散化。
vector<int> alls; // 儲存所有待離散化的值 sort(alls.begin(), alls.end()); // 將所有值排序 alls.erase(unique(alls.begin(), alls.end(), alls.end())); // 去掉重複元素 // 二分求出x對應的離散化的值 int find(int x) { int l = 0, r = alls.size() - 1; while (l < r) { int mid = l + r >> 1; if (alls[mid] >= x) r = mid; else l = mid + 1; } return r + 1; }
為什麼需要離散化?
一組數,每個數的大小範圍在 -1e9 到 +1e9 之間。
但是這些數很稀疏,在進行求這些數的和的操作時不可能遍歷所有的區間。
故而要使用離散化,將其對映到連續的陣列空間中。
例題
演算法
- 因為存在n次新增操作、2n次(l,r)查詢操作,在最壞的情況下他們都各不相同,故而構成對映的陣列空間是3 * 1e5 + 10 這麼大。
- 利用 pair<int,int> 儲存新增和查詢對。
- 第一步先將所有的數存入動態陣列空間(包括儲存的 x 和查詢的左右端點 l , r),進行排序、去重。
- 再將其值進行離散化查詢,通過二分查詢,找到其在陣列中的下標。
- 通過下標和其值,插入到建立好的陣列空間,求其字首和
- 通過字首和: arr[r] - arr[l - 1]得到區間和
C++實現
#include<iostream> #include<vector> #include<algorithm> using namespace std; typedef pair<int, int> PII; const int N = 300010; int n, m; int a[N], s[N]; vector<int> alls; vector<PII> add, query; int find (int x) { int l = 0, r = alls.size() - 1; while (l < r) { int mid = (l + r) >> 1; if (alls[mid] >= x) r = mid; else l = mid + 1; } return r + 1; } int main() { cin >> n >> m; for (int i = 0; i < n; i ++) { int x, c; cin >> x >> c; add.push_back({x, c}); alls.push_back(x); } for (int i = 0; i < m; i ++) { int l, r; cin >> l >> r; query.push_back({l, r}); alls.push_back(l); alls.push_back(r); } // 去重 sort(alls.begin(), alls.end()); alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 處理插入 for (auto item : add) { int x = find(item.first); a[x] += item.second; } // 預處理字首和 for (int i = 1; i <= alls.size(); i ++) s[i] = s[i - 1] + a[i]; // 處理詢問 for (auto item : query) { int l = find(item.first), r = find(item.second); cout << s[r] - s[l - 1] << endl; } return 0; }