Skip to content

feat: add solutions to lc problem: No.0699 #3328

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 113 additions & 4 deletions solution/0600-0699/0699.Falling Squares/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,14 @@ tags:

### 方法一:线段树

线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 $log(width)$。更新某个元素的值,只需要更新 $log(width)$ 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用**懒标记**保证效率。
根据题目描述,我们需要维护一个区间集合,支持区间的修改和查询操作。这种情况下,我们可以使用线段树来解决。

线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 $\log(width)$,其中 $width$ 是区间的长度。更新某个元素的值,只需要更新 $\log(width)$ 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用**懒标记**保证效率。

- 线段树的每个节点代表一个区间;
- 线段树具有唯一的根节点,代表的区间是整个统计范围,如 $[1, N]$;
- 线段树具有唯一的根节点,代表的区间是整个统计范围,如 $[1, n]$;
- 线段树的每个叶子节点代表一个长度为 1 的元区间 $[x, x]$;
- 对于每个内部节点 $[l, r]$,它的左儿子是 $[l, mid]$,右儿子是 $[mid + 1, r]$, 其中 $mid = ⌊(l + r) / 2⌋$ (即向下取整)。
- 对于每个内部节点 $[l, r]$,它的左儿子是 $[l, mid]$,右儿子是 $[mid + 1, r]$, 其中 $\textit{mid} = \frac{l + r}{2}$;

对于本题,线段树节点维护的信息有:

Expand All @@ -86,6 +88,8 @@ tags:

另外,由于数轴范围很大,达到 $10^8$,因此我们采用动态开点。

时间复杂度方面,每次查询和修改的时间复杂度为 $O(\log n)$,总时间复杂度为 $O(n \log n)$。空间复杂度为 $O(n)$。

<!-- tabs:start -->

#### Python3
Expand Down Expand Up @@ -388,7 +392,7 @@ func newNode(l, r int) *node {
return &node{
l: l,
r: r,
mid: int(uint(l+r) >> 1),
mid: (l + r) >> 1,
}
}

Expand Down Expand Up @@ -474,6 +478,111 @@ func fallingSquares(positions [][]int) []int {
}
```

#### TypeScript

```ts
class Node {
left: Node | null = null;
right: Node | null = null;
l: number;
r: number;
mid: number;
v: number = 0;
add: number = 0;

constructor(l: number, r: number) {
this.l = l;
this.r = r;
this.mid = (l + r) >> 1;
}
}

class SegmentTree {
private root: Node = new Node(1, 1e9);

public modify(l: number, r: number, v: number): void {
this.modifyNode(l, r, v, this.root);
}

private modifyNode(l: number, r: number, v: number, node: Node): void {
if (l > r) {
return;
}
if (node.l >= l && node.r <= r) {
node.v = v;
node.add = v;
return;
}
this.pushdown(node);
if (l <= node.mid) {
this.modifyNode(l, r, v, node.left!);
}
if (r > node.mid) {
this.modifyNode(l, r, v, node.right!);
}
this.pushup(node);
}

public query(l: number, r: number): number {
return this.queryNode(l, r, this.root);
}

private queryNode(l: number, r: number, node: Node): number {
if (l > r) {
return 0;
}
if (node.l >= l && node.r <= r) {
return node.v;
}
this.pushdown(node);
let v = 0;
if (l <= node.mid) {
v = Math.max(v, this.queryNode(l, r, node.left!));
}
if (r > node.mid) {
v = Math.max(v, this.queryNode(l, r, node.right!));
}
return v;
}

private pushup(node: Node): void {
node.v = Math.max(node.left!.v, node.right!.v);
}

private pushdown(node: Node): void {
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) {
let left = node.left,
right = node.right;
left!.add = node.add;
right!.add = node.add;
left!.v = node.add;
right!.v = node.add;
node.add = 0;
}
}
}

function fallingSquares(positions: number[][]): number[] {
const ans: number[] = [];
const tree = new SegmentTree();
let mx = 0;
for (const [l, w] of positions) {
const r = l + w - 1;
const h = tree.query(l, r) + w;
mx = Math.max(mx, h);
ans.push(mx);
tree.modify(l, r, h);
}
return ans;
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
127 changes: 125 additions & 2 deletions solution/0600-0699/0699.Falling Squares/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,25 @@ Note that square 2 only brushes the right side of square 1, which does not count

<!-- solution:start -->

### Solution 1
### Solution 1: Segment Tree

According to the problem description, we need to maintain a set of intervals that support modification and query operations. In this case, we can use a segment tree to solve the problem.

A segment tree divides the entire interval into multiple non-contiguous sub-intervals, with the number of sub-intervals not exceeding $\log(width)$, where $width$ is the length of the interval. To update the value of an element, we only need to update $\log(width)$ intervals, and these intervals are all contained within a larger interval that includes the element. When modifying intervals, we need to use **lazy propagation** to ensure efficiency.

- Each node of the segment tree represents an interval;
- The segment tree has a unique root node representing the entire statistical range, such as $[1, n]$;
- Each leaf node of the segment tree represents a primitive interval of length 1, $[x, x]$;
- For each internal node $[l, r]$, its left child is $[l, \textit{mid}]$, and its right child is $[\textit{mid} + 1, r]$, where $\textit{mid} = \frac{l + r}{2}$;

For this problem, the information maintained by the segment tree nodes includes:

1. The maximum height $v$ of the blocks in the interval
2. Lazy propagation marker $add$

Additionally, since the range of the number line is very large, up to $10^8$, we use dynamic node creation.

In terms of time complexity, each query and modification has a time complexity of $O(\log n)$, and the total time complexity is $O(n \log n)$. The space complexity is $O(n)$.

<!-- tabs:start -->

Expand Down Expand Up @@ -372,7 +390,7 @@ func newNode(l, r int) *node {
return &node{
l: l,
r: r,
mid: int(uint(l+r) >> 1),
mid: (l + r) >> 1,
}
}

Expand Down Expand Up @@ -458,6 +476,111 @@ func fallingSquares(positions [][]int) []int {
}
```

#### TypeScript

```ts
class Node {
left: Node | null = null;
right: Node | null = null;
l: number;
r: number;
mid: number;
v: number = 0;
add: number = 0;

constructor(l: number, r: number) {
this.l = l;
this.r = r;
this.mid = (l + r) >> 1;
}
}

class SegmentTree {
private root: Node = new Node(1, 1e9);

public modify(l: number, r: number, v: number): void {
this.modifyNode(l, r, v, this.root);
}

private modifyNode(l: number, r: number, v: number, node: Node): void {
if (l > r) {
return;
}
if (node.l >= l && node.r <= r) {
node.v = v;
node.add = v;
return;
}
this.pushdown(node);
if (l <= node.mid) {
this.modifyNode(l, r, v, node.left!);
}
if (r > node.mid) {
this.modifyNode(l, r, v, node.right!);
}
this.pushup(node);
}

public query(l: number, r: number): number {
return this.queryNode(l, r, this.root);
}

private queryNode(l: number, r: number, node: Node): number {
if (l > r) {
return 0;
}
if (node.l >= l && node.r <= r) {
return node.v;
}
this.pushdown(node);
let v = 0;
if (l <= node.mid) {
v = Math.max(v, this.queryNode(l, r, node.left!));
}
if (r > node.mid) {
v = Math.max(v, this.queryNode(l, r, node.right!));
}
return v;
}

private pushup(node: Node): void {
node.v = Math.max(node.left!.v, node.right!.v);
}

private pushdown(node: Node): void {
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) {
let left = node.left,
right = node.right;
left!.add = node.add;
right!.add = node.add;
left!.v = node.add;
right!.v = node.add;
node.add = 0;
}
}
}

function fallingSquares(positions: number[][]): number[] {
const ans: number[] = [];
const tree = new SegmentTree();
let mx = 0;
for (const [l, w] of positions) {
const r = l + w - 1;
const h = tree.query(l, r) + w;
mx = Math.max(mx, h);
ans.push(mx);
tree.modify(l, r, h);
}
return ans;
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
2 changes: 1 addition & 1 deletion solution/0600-0699/0699.Falling Squares/Solution.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func newNode(l, r int) *node {
return &node{
l: l,
r: r,
mid: int(uint(l+r) >> 1),
mid: (l + r) >> 1,
}
}

Expand Down
Loading
Loading