给你区间的 空 集,请你设计并实现满足要求的数据结构:
- 新增:添加一个区间到这个区间集合中。
- 统计:计算出现在 至少一个 区间中的整数个数。
实现 CountIntervals
类:
CountIntervals()
使用区间的空集初始化对象void add(int left, int right)
添加区间[left, right]
到区间集合之中。int count()
返回出现在 至少一个 区间中的整数个数。
注意:区间 [left, right]
表示满足 left <= x <= right
的所有整数 x
。
示例 1:
输入 ["CountIntervals", "add", "add", "count", "add", "count"] [[], [2, 3], [7, 10], [], [5, 8], []] 输出 [null, null, null, 6, null, 8] 解释 CountIntervals countIntervals = new CountIntervals(); // 用一个区间空集初始化对象 countIntervals.add(2, 3); // 将 [2, 3] 添加到区间集合中 countIntervals.add(7, 10); // 将 [7, 10] 添加到区间集合中 countIntervals.count(); // 返回 6 // 整数 2 和 3 出现在区间 [2, 3] 中 // 整数 7、8、9、10 出现在区间 [7, 10] 中 countIntervals.add(5, 8); // 将 [5, 8] 添加到区间集合中 countIntervals.count(); // 返回 8 // 整数 2 和 3 出现在区间 [2, 3] 中 // 整数 5 和 6 出现在区间 [5, 8] 中 // 整数 7 和 8 出现在区间 [5, 8] 和区间 [7, 10] 中 // 整数 9 和 10 出现在区间 [7, 10] 中
提示:
1 <= left <= right <= 109
- 最多调用
add
和count
方法 总计105
次 - 调用
count
方法至少一次
方法一:线段树
区间求和问题,且值域较大,采用动态开点线段树。
class Node:
def __init__(self):
self.tag = 0
self.tot = 0
self.left = None
self.right = None
def update(self, l, r, a, b):
if self.tag == 1:
return
mid = (a + b) >> 1
if l == a and r == b:
self.tag = 1
self.tot = b - a + 1
return
if not self.left:
self.left = Node()
if not self.right:
self.right = Node()
if mid >= l:
self.left.update(l, min(mid, r), a, mid)
if mid + 1 <= r:
self.right.update(max(mid + 1, l), r, mid + 1, b)
self.tag = 0
self.tot = self.left.tot + self.right.tot
class CountIntervals:
def __init__(self):
self.tree = Node()
def add(self, left: int, right: int) -> None:
self.tree.update(left, right, 0, 1000000010)
def count(self) -> int:
return self.tree.tot
# Your CountIntervals object will be instantiated and called as such:
# obj = CountIntervals()
# obj.add(left,right)
# param_2 = obj.count()
class Node {
Node left;
Node right;
int l;
int r;
int mid;
int v;
int add;
public Node(int l, int r) {
this.l = l;
this.r = r;
this.mid = (l + r) >> 1;
}
}
class SegmentTree {
private Node root = new Node(1, (int) 1e9 + 1);
public SegmentTree() {
}
public void modify(int l, int r, int v) {
modify(l, r, v, root);
}
public void modify(int l, int r, int v, Node node) {
if (l > r) {
return;
}
if (node.l >= l && node.r <= r) {
node.v = node.r - node.l + 1;
node.add = v;
return;
}
pushdown(node);
if (l <= node.mid) {
modify(l, r, v, node.left);
}
if (r > node.mid) {
modify(l, r, v, node.right);
}
pushup(node);
}
public int query(int l, int r) {
return query(l, r, root);
}
public int query(int l, int r, Node node) {
if (l > r) {
return 0;
}
if (node.l >= l && node.r <= r) {
return node.v;
}
pushdown(node);
int v = 0;
if (l <= node.mid) {
v += query(l, r, node.left);
}
if (r > node.mid) {
v += query(l, r, node.right);
}
return v;
}
public void pushup(Node node) {
node.v = node.left.v + node.right.v;
}
public void pushdown(Node node) {
if (node.left == null) {
node.left = new Node(node.l, node.mid);
}
if (node.right == null) {
node.right = new Node(node.mid + 1, node.r);
}
if (node.add != 0) {
Node left = node.left, right = node.right;
left.add = node.add;
right.add = node.add;
left.v = left.r - left.l + 1;
right.v = right.r - right.l + 1;
node.add = 0;
}
}
}
class CountIntervals {
private SegmentTree tree = new SegmentTree();
public CountIntervals() {
}
public void add(int left, int right) {
tree.modify(left, right, 1);
}
public int count() {
return tree.query(1, (int) 1e9);
}
}
/**
* Your CountIntervals object will be instantiated and called as such:
* CountIntervals obj = new CountIntervals();
* obj.add(left,right);
* int param_2 = obj.count();
*/
class CountIntervals {
left: null | CountIntervals;
right: null | CountIntervals;
start: number;
end: number;
sum: number;
constructor(start: number = 0, end: number = 10 ** 9) {
this.left = null;
this.right = null;
this.start = start;
this.end = end;
this.sum = 0;
}
add(left: number, right: number): void {
if (this.sum == this.end - this.start + 1) return;
if (left <= this.start && right >= this.end) {
this.sum = this.end - this.start + 1;
return;
}
let mid = (this.start + this.end) >> 1;
if (!this.left) this.left = new CountIntervals(this.start, mid);
if (!this.right) this.right = new CountIntervals(mid + 1, this.end);
if (left <= mid) this.left.add(left, right);
if (right > mid) this.right.add(left, right);
this.sum = this.left.sum + this.right.sum;
}
count(): number {
return this.sum;
}
}
/**
* Your CountIntervals object will be instantiated and called as such:
* var obj = new CountIntervals()
* obj.add(left,right)
* var param_2 = obj.count()
*/