[SHOI2009] 会场预约

GitHub跳转原题关系图返回列表

Fenwick 维护当前不相交线段的起点,并按秩寻找可能相交的前驱和后继。

OJ: luogu

题目 ID: P2161

难度:提高+/省选-

标签:树状数组有序集合线段python

日期: 2026-07-16 21:00

题意

插入新区间时删除所有与它相交的旧区间并输出删除数;另支持查询当前区间数。

思路

集合中的旧区间始终两两不交,因此按起点有序。日期上界只有 10^5,Fenwick 在每个起点保存是否存在区间,end_at[start] 保存终点。

先找起点不超过新左端的最后一条,检查它是否延伸到左端;再反复找第一个起点不小于左端的区间,直到起点超过新右端。每条被删线段都做一次 Fenwick 删除,最后加入新区间。

Python 知识

  • Fenwick 的 kth(rank) 用二进制提升实现动态集合按秩查找。
  • bytes 操作码直接与 b"B" 比较。
  • 所有历史删除总数不超过插入总数,循环总成本仍是线性的删除次数乘对数。

代码

python
import sys


MAXIMUM = 100000
input = sys.stdin.buffer.readline
tree = [0] * (MAXIMUM + 1)
end_at = [0] * (MAXIMUM + 1)
active = 0


def add(index, delta):
    while index <= MAXIMUM:
        tree[index] += delta
        index += index & -index


def prefix(index):
    result = 0
    while index:
        result += tree[index]
        index -= index & -index
    return result


def kth(rank):
    index = 0
    step = 1 << (MAXIMUM.bit_length() - 1)
    while step:
        target = index + step
        if target <= MAXIMUM and tree[target] < rank:
            index = target
            rank -= tree[target]
        step >>= 1
    return index + 1


answers = []
for _ in range(int(input())):
    operation = input().split()
    if operation[0] == b"B":
        answers.append(str(active))
        continue
    left, right = map(int, operation[1:])
    removed = 0
    before = prefix(left)
    if before:
        start = kth(before)
        if end_at[start] >= left:
            add(start, -1)
            end_at[start] = 0
            active -= 1
            removed += 1
    while prefix(MAXIMUM) > prefix(left - 1):
        start = kth(prefix(left - 1) + 1)
        if start > right:
            break
        add(start, -1)
        end_at[start] = 0
        active -= 1
        removed += 1
    add(left, 1)
    end_at[left] = right
    active += 1
    answers.append(str(removed))

print("\n".join(answers))

复杂度

每次查找/修改 O(logC)O(\log C),所有删除合计 O(n)O(n),总时间 O(nlogC)O(n\log C),空间 O(C)O(C),其中 C=105C=10^5

总结

值域较小时,Fenwick 加按秩查询可以替代平衡树维护动态有序起点集合。