賓館有 n 個房間,支持兩種操作:
1 d:查詢最左邊的連續 d 個空房間的起始位置
2 x d:將從 x 開始的連續 d 個房間標記為空閒
每個節點維護區間 [l, r] 的三個值:
lm:從左端點開始的最大連續空房間數rm:從右端點開始的最大連續空房間數mx:區間內最大連續空房間數
void pushup(int rt, int l, int r) {
int m = (l + r) >> 1;
int lc = rt << 1, rc = rt << 1 | 1;
node[rt].mx = max({node[lc].mx, node[rc].mx, node[lc].rm + node[rc].lm});
node[rt].lm = node[lc].lm;
if (node[lc].lm == m - l + 1) // 左子區間全空
node[rt].lm += node[rc].lm;
node[rt].rm = node[rc].rm;
if (node[rc].rm == r - m) // 右子區間全空
node[rt].rm += node[lc].rm;
}
int query(int d, int l, int r, int rt) {
if (l == r) return l;
pushdown(rt, l, r);
int m = (l + r) >> 1;
if (node[rt<<1].mx >= d) return query(d, l, m, rt<<1);
if (node[rt<<1].rm + node[rt<<1|1].lm >= d) return m - node[rt<<1].rm + 1;
return query(d, m+1, r, rt<<1|1);
}
單次操作 O(log n),總時間 O((n+m) log n),空間 O(n)。