高度 h、寬度 w 的佈告欄(h, w ≤ 10^9)。依次投放 n 條廣告(n ≤ 200,000),第 i 條寬度 w_i、高度 1。規則:
輸出每條廣告放置的行號(1-indexed)。
雖然 h ≤ 10^9,但最多只能放 n 條廣告,實際只需建立 min(h, n) 行的線段樹。
每個節點存儲該區間內的最大剩餘寬度 maxWidth。
struct Node {
int l, r;
int maxWidth; // 區間內最大可用寬度
} tree[MAXN * 4];
void build(int l, int r, int idx) {
tree[idx].l = l; tree[idx].r = r;
tree[idx].maxWidth = w;
if (l == r) return;
int mid = (l + r) >> 1;
build(l, mid, idx << 1);
build(mid + 1, r, idx << 1 | 1);
}
int query(int width, int idx) {
if (tree[idx].l == tree[idx].r) { // 葉子節點:具體行
tree[idx].maxWidth -= width;
return tree[idx].l; // 返回行號
}
// 優先查左子樹(上方行)
if (tree[idx<<1].maxWidth >= width)
return query(width, idx << 1);
else
return query(width, idx << 1 | 1);
}
#include#include #include using namespace std; const int MAXN = 200010; struct Node { int l, r, maxWidth; } tree[MAXN * 4]; int h, w, n; int main() { while (scanf("%d%d%d", &h, &w, &n) == 3) { int rows = min(h, n); build(1, rows, 1); for (int i = 0; i < n; ++i) { int wi; scanf("%d", &wi); if (tree[1].maxWidth < wi) { printf("-1\n"); } else { printf("%d\n", query(wi, 1)); } } } return 0; }
輸入: 3 5 5
2 4 3 3 3
過程:
行1: 放寬度2 → 剩餘3
行2: 放寬度4 → 剩餘1
行1: 放寬度3 → 剩餘0
行3: 放寬度3 → 剩餘2
行1/2/3均無法放寬度3 → -1
輸出: 1 2 1 3 -1
| 操作 | 時間複雜度 | 說明 |
|---|---|---|
| 建樹 | O(min(h,n)) | 最多 200,000 節點 |
| 單次查詢/更新 | O(log min(h,n)) | 從根到葉子路徑 |
| 總體 | O(n log n) | n ≤ 200,000,極快 |
min(h, n) 避免 10^9 空間爆炸