洛谷P5250 【深基17.例5】木材倉庫

Tomorrowland_D發表於2024-08-06

【深基17.例5】木材倉庫

題目描述

博艾市有一個木材倉庫,裡面可以儲存各種長度的木材,但是保證沒有兩個木材的長度是相同的。作為倉庫負責人,你有時候會進貨,有時候會出貨,因此需要維護這個庫存。有不超過 100000 條的操作:

  • 進貨,格式1 Length:在倉庫中放入一根長度為 Length(不超過 \(10^9\)) 的木材。如果已經有相同長度的木材那麼輸出Already Exist
  • 出貨,格式2 Length:從倉庫中取出長度為 Length 的木材。如果沒有剛好長度的木材,取出倉庫中存在的和要求長度最接近的木材。如果有多根木材符合要求,取出比較短的一根。輸出取出的木材長度。如果倉庫是空的,輸出Empty

輸入格式

輸出格式

樣例 #1

樣例輸入 #1

7
1 1
1 5
1 3
2 3
2 3
2 3
2 3

樣例輸出 #1

3
1
5
Empty

思路:

  • 這題我們觀察到要快速查詢倉庫中是否存在length長度的木材,而且還要讓長度為length的木材出庫,有這兩個特性我們會自然而然的想到set,能夠快速檢索,並且還能快速刪除集合中的某一個元素。
  • 首先,我們定義一個set,然後迴圈n次操作,如果x==1的話,我們就查詢,查到了就輸出Already Exist,並換行。否則,就進入x=2的邏輯,先判斷set是否為空,為空我們就輸出empty,否則我們就利用lower_bound來查詢到第一個大於等於length的位置
  • 讓指標i指向set中第一個≥length的位置,先讓指標j與指標i指向相同的位置。並且判斷i的兩個特殊情況:
  1. i指向s.begin()的位置,此時將j賦值為i(不動即可),此時的j就是我們要刪除的位置,並記得在刪除之前先輸出一下
  2. i指向s.end()的位置,此時將j賦值為i-1的位置,就是set中最後一個元素的位置,此時j就是我們要出庫的那根木材
  3. 如果i在中間的某一個位置,我們得判斷i-1的位置和i的位置哪一個距離length更近,因為lower_bound只是能找出第一個≥length的位置,並不能直接判斷上一個位置和找到的這個位置與檢索的值哪一個距離更近,因此,我們先讓j--,然後判斷二者距離length的位置誰更近,如果i距離length更近,只需要將j重新賦值給i就行了
				else {
					j--;
					if (*i - length < length - *j) j = i;
				}
  1. 最後,記得輸出j所指向的位置,並在集合中刪除j指向的元素即可
				cout << *j << endl;
				//這裡可以寫*j,也可以只寫j,只寫j表明刪除j這個迭代器所對應的位置,寫*j表明刪除j所指向的這個元素
				s.erase(*j);

程式碼:

#include<set>
#include<iostream>
using namespace std;
int n;
int x, length;
set<int> s;
int main()
{
	cin >> n;
	while (n--) {
		cin >> x >> length;
		if (x == 1) {
			if (s.find(length) == s.end()) s.insert(length);
			else cout << "Already Exist" << endl;
		}
		else if (x == 2) {
			if (s.empty()) cout << "Empty" << endl;
			else {
				auto i = lower_bound(s.begin(),s.end(), length);
				auto j = i;
				if (i == s.begin()) j = i;
				else if (i == s.end()) {
					i--; j = i;
				}
				else {
					j--;
					if (*i - length < length - *j) j = i;
				}
				cout << *j << endl;
				s.erase(*j);
			}
		}
	}
	return 0;
}