【HAOI2008】糖果傳遞-貪心
阿新 • • 發佈:2020-07-18
離散化:離散化就是把大範圍的數,對映到一個小範圍,即把無限空間中的有限個體,對映到有限空間中去,以此來提高演算法的時空效率。
例題:求區間和
假定有一個無限長的數軸,數軸上每個座標上的數都是0。
現在,我們首先進行n次操作,每次操作將某一位置x上的數加c。
接下來,進行m次詢問,每個詢問包含兩個整數l和r,你需要求出在區間[l,r]之間的所有數的和。
輸入格式
第一行包含兩個整數n和m。
接下來n行,每行包含兩個整數x和c。
再接下里m行,每行包含兩個整數l和r。
輸出格式
共m行,每行輸出一個詢問中所求的區間內數字和。
資料範圍
−109 ≤ x ≤ 109,
1 ≤ n,m ≤ 105,
−109 ≤ l ≤ r ≤ 109,
−10000 ≤ c ≤ 10000
輸入樣例:
33
12
36
75
13
46
78
輸出樣例:
8
0
5
思路:看到這道題想到的肯定是利用字首和進行計算,但是如果直接使用字首和的話我們需要開一個數量級為1e9的陣列,這顯然不太可能,而發現n與m最多就訪問1e5次,所以我們用的空間最多數量級也就1e5,所以 n m x 一共用到的空間是3 e5就足夠了,因此我們就把用到的數都通過離散化對映到小範圍中去,再使用字首和。
那麼離散化的方法:首先把所有要離散化的資料都push_back()到all陣列中去,然後先排序,再去重,再利用二分來離散化。
排序:
1 sort(alls.begin(), alls.end());
去重:運用erase,unique來去重(經典方法)
1 alls.erase(unique(alls.begin(), alls.end()), alls.end());
unique的去重原理是將所用不重複的元素放到前邊,將重複的元素放到陣列後邊,最後將迭代器指向最後不重複下標並返回,所以這個操作完美去重。
離散化:即運用二分,也可直接用low_bound,把數插入到a陣列中去。
二分寫法:因為是用到字首和,所以我們的下標從1開始,返回的是r+1
1 int find(int x) 2 { 3 int l = 0, r = alls.size()-1; 4 while(l < r) 5 { 6 int mid = l+r >> 1; 7 if(alls[mid] >= x) r = mid; //依據的是原先數字在alls陣列中的相對位置 8 else l = mid+1; 9 }10 11 return r+1; 12 }
low_bound()寫法:
1 int find(int x) //lower_bound二分寫法 2 { 3 return lower_bound(alls.begin(), alls.end(), x) - alls.begin() + 1; 4 }
總程式碼
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 typedef pair<int, int> PII; 8 9 const int N = 300010; 10 int n, m; 11 int a[N], s[N]; //a存放離散化後的序列 12 13 vector<int> alls; //要散化的所有資料 14 vector<PII> add, query; //add是存x+c的 query用來存區間兩邊 15 16 int find(int x) 17 { 18 int l = 0, r = alls.size()-1; 19 while(l < r) 20 { 21 int mid = l+r >> 1; 22 if(alls[mid] >= x) r = mid; //依據的是原先數字在alls陣列中的相對位置 23 else l = mid+1; 24 } 25 26 return r+1; 27 } 28 29 int main() 30 { 31 cin >> n >> m; 32 for(int i = 0; i < n; i++) 33 { 34 int x, c; 35 cin >> x >> c; 36 add.push_back({x, c}); //在某個數上加c 37 38 alls.push_back(x); 39 } 40 41 for(int i = 0; i < m; i++) 42 { 43 int l, r; 44 cin >> l >> r; 45 query.push_back({l, r}); 46 47 alls.push_back(l); 48 alls.push_back(r); 49 } 50 51 //去重 52 sort(alls.begin(), alls.end()); 53 alls.erase(unique(alls.begin(), alls.end()), alls.end()); 54 55 //處理插入 56 for(auto item : add) 57 { 58 int x = find(item.first); 59 a[x] += item.second; 60 } 61 62 //預處理字首和 63 for(int i = 1; i <= alls.size(); i++) s[i] = s[i-1] + a[i]; 64 65 //處理詢問 66 for(auto item : query) 67 { 68 int l = find(item.first), r = find(item.second); 69 cout << s[r] - s[l-1] << endl; 70 } 71 system("pause"); 72 return 0; 73 }