diff --git a/solution/2600-2699/2612.Minimum Reverse Operations/README.md b/solution/2600-2699/2612.Minimum Reverse Operations/README.md index c616eafebb255..49a46fe26c70a 100644 --- a/solution/2600-2699/2612.Minimum Reverse Operations/README.md +++ b/solution/2600-2699/2612.Minimum Reverse Operations/README.md @@ -254,8 +254,8 @@ func minReverseOperations(n int, p int, banned []int, k int) []int { ```ts function minReverseOperations(n: number, p: number, banned: number[], k: number): number[] { - const ans = new Array(n).fill(-1); - const ts = new Array(2).fill(0).map(() => new TreeSet()); + const ans: number[] = Array(n).fill(-1); + const ts = [new TreeSet(), new TreeSet()]; for (let i = 0; i < n; ++i) { ts[i % 2].add(i); } @@ -925,665 +925,44 @@ class TreeMultiSet { } ``` - - - - - - -### 方法二 - - - -#### TypeScript - -```ts -function minReverseOperations(n: number, p: number, banned: number[], k: number): number[] { - const ans = new Array(n).fill(-1); - const ts = new Array(2).fill(0).map(() => new TreapMultiSet()); - for (let i = 0; i < n; ++i) { - ts[i % 2].add(i); - } - ans[p] = 0; - ts[p % 2].delete(p); - for (const i of banned) { - ts[i % 2].delete(i); - } - ts[0].add(n); - ts[1].add(n); - let q = [p]; - while (q.length) { - const t: number[] = []; - for (const i of q) { - const mi = Math.max(i - k + 1, k - i - 1); - const mx = Math.min(i + k - 1, n * 2 - k - i - 1); - const s = ts[mi % 2]; - for (let j = s.ceil(mi)!; j <= mx; j = s.ceil(j)!) { - t.push(j); - ans[j] = ans[i] + 1; - s.delete(j); - } - } - q = t; - } - return ans; -} - -type CompareFunction = ( - a: T, - b: T, -) => R extends 'number' ? number : boolean; - -interface ITreapMultiSet extends Iterable { - add: (...value: T[]) => this; - has: (value: T) => boolean; - delete: (value: T) => void; - - bisectLeft: (value: T) => number; - bisectRight: (value: T) => number; - - indexOf: (value: T) => number; - lastIndexOf: (value: T) => number; - - at: (index: number) => T | undefined; - first: () => T | undefined; - last: () => T | undefined; - - lower: (value: T) => T | undefined; - higher: (value: T) => T | undefined; - floor: (value: T) => T | undefined; - ceil: (value: T) => T | undefined; - - shift: () => T | undefined; - pop: (index?: number) => T | undefined; - - count: (value: T) => number; - - keys: () => IterableIterator; - values: () => IterableIterator; - rvalues: () => IterableIterator; - entries: () => IterableIterator<[number, T]>; - - readonly size: number; -} - -class TreapNode { - value: T; - count: number; - size: number; - priority: number; - left: TreapNode | null; - right: TreapNode | null; - - constructor(value: T) { - this.value = value; - this.count = 1; - this.size = 1; - this.priority = Math.random(); - this.left = null; - this.right = null; - } - - static getSize(node: TreapNode | null): number { - return node?.size ?? 0; - } - - static getFac(node: TreapNode | null): number { - return node?.priority ?? 0; - } - - pushUp(): void { - let tmp = this.count; - tmp += TreapNode.getSize(this.left); - tmp += TreapNode.getSize(this.right); - this.size = tmp; - } - - rotateRight(): TreapNode { - // eslint-disable-next-line @typescript-eslint/no-this-alias - let node: TreapNode = this; - const left = node.left; - node.left = left?.right ?? null; - left && (left.right = node); - left && (node = left); - node.right?.pushUp(); - node.pushUp(); - return node; - } - - rotateLeft(): TreapNode { - // eslint-disable-next-line @typescript-eslint/no-this-alias - let node: TreapNode = this; - const right = node.right; - node.right = right?.left ?? null; - right && (right.left = node); - right && (node = right); - node.left?.pushUp(); - node.pushUp(); - return node; - } -} - -class TreapMultiSet implements ITreapMultiSet { - private readonly root: TreapNode; - private readonly compareFn: CompareFunction; - private readonly leftBound: T; - private readonly rightBound: T; - - constructor(compareFn?: CompareFunction); - constructor(compareFn: CompareFunction, leftBound: T, rightBound: T); - constructor( - compareFn: CompareFunction = (a: any, b: any) => a - b, - leftBound: any = -Infinity, - rightBound: any = Infinity, - ) { - this.root = new TreapNode(rightBound); - this.root.priority = Infinity; - this.root.left = new TreapNode(leftBound); - this.root.left.priority = -Infinity; - this.root.pushUp(); - - this.leftBound = leftBound; - this.rightBound = rightBound; - this.compareFn = compareFn; - } - - get size(): number { - return this.root.size - 2; - } - - get height(): number { - const getHeight = (node: TreapNode | null): number => { - if (node == null) return 0; - return 1 + Math.max(getHeight(node.left), getHeight(node.right)); - }; - - return getHeight(this.root); - } - - /** - * - * @complexity `O(logn)` - * @description Returns true if value is a member. - */ - has(value: T): boolean { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): boolean => { - if (node == null) return false; - if (compare(node.value, value) === 0) return true; - if (compare(node.value, value) < 0) return dfs(node.right, value); - return dfs(node.left, value); - }; - - return dfs(this.root, value); - } - - /** - * - * @complexity `O(logn)` - * @description Add value to sorted set. - */ - add(...values: T[]): this { - const compare = this.compareFn; - const dfs = ( - node: TreapNode | null, - value: T, - parent: TreapNode, - direction: 'left' | 'right', - ): void => { - if (node == null) return; - if (compare(node.value, value) === 0) { - node.count++; - node.pushUp(); - } else if (compare(node.value, value) > 0) { - if (node.left) { - dfs(node.left, value, node, 'left'); - } else { - node.left = new TreapNode(value); - node.pushUp(); - } - - if (TreapNode.getFac(node.left) > node.priority) { - parent[direction] = node.rotateRight(); - } - } else if (compare(node.value, value) < 0) { - if (node.right) { - dfs(node.right, value, node, 'right'); - } else { - node.right = new TreapNode(value); - node.pushUp(); - } - - if (TreapNode.getFac(node.right) > node.priority) { - parent[direction] = node.rotateLeft(); - } - } - parent.pushUp(); - }; - - values.forEach(value => dfs(this.root.left, value, this.root, 'left')); - return this; - } - - /** - * - * @complexity `O(logn)` - * @description Remove value from sorted set if it is a member. - * If value is not a member, do nothing. - */ - delete(value: T): void { - const compare = this.compareFn; - const dfs = ( - node: TreapNode | null, - value: T, - parent: TreapNode, - direction: 'left' | 'right', - ): void => { - if (node == null) return; - - if (compare(node.value, value) === 0) { - if (node.count > 1) { - node.count--; - node?.pushUp(); - } else if (node.left == null && node.right == null) { - parent[direction] = null; - } else { - // 旋到根节点 - if ( - node.right == null || - TreapNode.getFac(node.left) > TreapNode.getFac(node.right) - ) { - parent[direction] = node.rotateRight(); - dfs(parent[direction]?.right ?? null, value, parent[direction]!, 'right'); - } else { - parent[direction] = node.rotateLeft(); - dfs(parent[direction]?.left ?? null, value, parent[direction]!, 'left'); - } - } - } else if (compare(node.value, value) > 0) { - dfs(node.left, value, node, 'left'); - } else if (compare(node.value, value) < 0) { - dfs(node.right, value, node, 'right'); - } - - parent?.pushUp(); - }; - - dfs(this.root.left, value, this.root, 'left'); - } - - /** - * - * @complexity `O(logn)` - * @description Returns an index to insert value in the sorted set. - * If the value is already present, the insertion point will be before (to the left of) any existing values. - */ - bisectLeft(value: T): number { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - return TreapNode.getSize(node.left); - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - - return dfs(this.root, value) - 1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns an index to insert value in the sorted set. - * If the value is already present, the insertion point will be before (to the right of) any existing values. - */ - bisectRight(value: T): number { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - return TreapNode.getSize(node.left) + node.count; - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - return dfs(this.root, value) - 1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns the index of the first occurrence of a value in the set, or -1 if it is not present. - */ - indexOf(value: T): number { - const compare = this.compareFn; - let isExist = false; - - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - isExist = true; - return TreapNode.getSize(node.left); - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - const res = dfs(this.root, value) - 1; - return isExist ? res : -1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns the index of the last occurrence of a value in the set, or -1 if it is not present. - */ - lastIndexOf(value: T): number { - const compare = this.compareFn; - let isExist = false; - - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - isExist = true; - return TreapNode.getSize(node.left) + node.count - 1; - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - - const res = dfs(this.root, value) - 1; - return isExist ? res : -1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns the item located at the specified index. - * @param index The zero-based index of the desired code unit. A negative index will count back from the last item. - */ - at(index: number): T | undefined { - if (index < 0) index += this.size; - if (index < 0 || index >= this.size) return undefined; - - const dfs = (node: TreapNode | null, rank: number): T | undefined => { - if (node == null) return undefined; - - if (TreapNode.getSize(node.left) >= rank) { - return dfs(node.left, rank); - } else if (TreapNode.getSize(node.left) + node.count >= rank) { - return node.value; - } else { - return dfs(node.right, rank - TreapNode.getSize(node.left) - node.count); - } - }; - - const res = dfs(this.root, index + 2); - return ([this.leftBound, this.rightBound] as any[]).includes(res) ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element less than `val`, return `undefined` if no such element found. - */ - lower(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) >= 0) return dfs(node.left, value); - - const tmp = dfs(node.right, value); - if (tmp == null || compare(node.value, tmp) > 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.leftBound ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element greater than `val`, return `undefined` if no such element found. - */ - higher(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) <= 0) return dfs(node.right, value); - - const tmp = dfs(node.left, value); - - if (tmp == null || compare(node.value, tmp) < 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.rightBound ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element less than or equal to `val`, return `undefined` if no such element found. - */ - floor(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) === 0) return node.value; - if (compare(node.value, value) >= 0) return dfs(node.left, value); - - const tmp = dfs(node.right, value); - if (tmp == null || compare(node.value, tmp) > 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.leftBound ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element greater than or equal to `val`, return `undefined` if no such element found. - */ - ceil(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) === 0) return node.value; - if (compare(node.value, value) <= 0) return dfs(node.right, value); - - const tmp = dfs(node.left, value); +#### Rust - if (tmp == null || compare(node.value, tmp) < 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.rightBound ? undefined : res; - } - - /** - * @complexity `O(logn)` - * @description - * Returns the last element from set. - * If the set is empty, undefined is returned. - */ - first(): T | undefined { - const iter = this.inOrder(); - iter.next(); - const res = iter.next().value; - return res === this.rightBound ? undefined : res; - } - - /** - * @complexity `O(logn)` - * @description - * Returns the last element from set. - * If the set is empty, undefined is returned . - */ - last(): T | undefined { - const iter = this.reverseInOrder(); - iter.next(); - const res = iter.next().value; - return res === this.leftBound ? undefined : res; - } - - /** - * @complexity `O(logn)` - * @description - * Removes the first element from an set and returns it. - * If the set is empty, undefined is returned and the set is not modified. - */ - shift(): T | undefined { - const first = this.first(); - if (first === undefined) return undefined; - this.delete(first); - return first; - } - - /** - * @complexity `O(logn)` - * @description - * Removes the last element from an set and returns it. - * If the set is empty, undefined is returned and the set is not modified. - */ - pop(index?: number): T | undefined { - if (index == null) { - const last = this.last(); - if (last === undefined) return undefined; - this.delete(last); - return last; - } - - const toDelete = this.at(index); - if (toDelete == null) return; - this.delete(toDelete); - return toDelete; - } - - /** - * - * @complexity `O(logn)` - * @description - * Returns number of occurrences of value in the sorted set. - */ - count(value: T): number { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - if (compare(node.value, value) === 0) return node.count; - if (compare(node.value, value) < 0) return dfs(node.right, value); - return dfs(node.left, value); - }; - - return dfs(this.root, value); - } - - *[Symbol.iterator](): Generator { - yield* this.values(); - } +```rust +use std::collections::{BTreeSet, VecDeque}; - /** - * @description - * Returns an iterable of keys in the set. - */ - *keys(): Generator { - yield* this.values(); - } - - /** - * @description - * Returns an iterable of values in the set. - */ - *values(): Generator { - const iter = this.inOrder(); - iter.next(); - const steps = this.size; - for (let _ = 0; _ < steps; _++) { - yield iter.next().value; - } - } +impl Solution { + pub fn min_reverse_operations(n: i32, p: i32, banned: Vec, k: i32) -> Vec { + let mut ans = vec![-1; n as usize]; + let mut ts = [BTreeSet::new(), BTreeSet::new()]; - /** - * @description - * Returns a generator for reversed order traversing the set. - */ - *rvalues(): Generator { - const iter = this.reverseInOrder(); - iter.next(); - const steps = this.size; - for (let _ = 0; _ < steps; _++) { - yield iter.next().value; + for i in 0..n { + ts[(i % 2) as usize].insert(i); } - } + ans[p as usize] = 0; + ts[(p % 2) as usize].remove(&p); - /** - * @description - * Returns an iterable of key, value pairs for every entry in the set. - */ - *entries(): IterableIterator<[number, T]> { - const iter = this.inOrder(); - iter.next(); - const steps = this.size; - for (let i = 0; i < steps; i++) { - yield [i, iter.next().value]; + for &b in &banned { + ts[(b % 2) as usize].remove(&b); } - } - private *inOrder(root: TreapNode | null = this.root): Generator { - if (root == null) return; - yield* this.inOrder(root.left); - const count = root.count; - for (let _ = 0; _ < count; _++) { - yield root.value; + ts[0].insert(n); + ts[1].insert(n); + let mut q = VecDeque::new(); + q.push_back(p); + + while let Some(i) = q.pop_front() { + let mi = (i - k + 1).max(k - i - 1); + let mx = (i + k - 1).min(2 * n - k - i - 1); + let s = &mut ts[(mi % 2) as usize]; + + while let Some(&j) = s.range(mi..=mx).next() { + q.push_back(j); + ans[j as usize] = ans[i as usize] + 1; + s.remove(&j); + } } - yield* this.inOrder(root.right); - } - private *reverseInOrder(root: TreapNode | null = this.root): Generator { - if (root == null) return; - yield* this.reverseInOrder(root.right); - const count = root.count; - for (let _ = 0; _ < count; _++) { - yield root.value; - } - yield* this.reverseInOrder(root.left); + ans } } ``` diff --git a/solution/2600-2699/2612.Minimum Reverse Operations/README_EN.md b/solution/2600-2699/2612.Minimum Reverse Operations/README_EN.md index 31d61dd3a3fbe..b9528870bbb32 100644 --- a/solution/2600-2699/2612.Minimum Reverse Operations/README_EN.md +++ b/solution/2600-2699/2612.Minimum Reverse Operations/README_EN.md @@ -263,8 +263,8 @@ func minReverseOperations(n int, p int, banned []int, k int) []int { ```ts function minReverseOperations(n: number, p: number, banned: number[], k: number): number[] { - const ans = new Array(n).fill(-1); - const ts = new Array(2).fill(0).map(() => new TreeSet()); + const ans: number[] = Array(n).fill(-1); + const ts = [new TreeSet(), new TreeSet()]; for (let i = 0; i < n; ++i) { ts[i % 2].add(i); } @@ -934,665 +934,44 @@ class TreeMultiSet { } ``` - - - - - - -### Solution 2 - - - -#### TypeScript - -```ts -function minReverseOperations(n: number, p: number, banned: number[], k: number): number[] { - const ans = new Array(n).fill(-1); - const ts = new Array(2).fill(0).map(() => new TreapMultiSet()); - for (let i = 0; i < n; ++i) { - ts[i % 2].add(i); - } - ans[p] = 0; - ts[p % 2].delete(p); - for (const i of banned) { - ts[i % 2].delete(i); - } - ts[0].add(n); - ts[1].add(n); - let q = [p]; - while (q.length) { - const t: number[] = []; - for (const i of q) { - const mi = Math.max(i - k + 1, k - i - 1); - const mx = Math.min(i + k - 1, n * 2 - k - i - 1); - const s = ts[mi % 2]; - for (let j = s.ceil(mi)!; j <= mx; j = s.ceil(j)!) { - t.push(j); - ans[j] = ans[i] + 1; - s.delete(j); - } - } - q = t; - } - return ans; -} - -type CompareFunction = ( - a: T, - b: T, -) => R extends 'number' ? number : boolean; - -interface ITreapMultiSet extends Iterable { - add: (...value: T[]) => this; - has: (value: T) => boolean; - delete: (value: T) => void; - - bisectLeft: (value: T) => number; - bisectRight: (value: T) => number; - - indexOf: (value: T) => number; - lastIndexOf: (value: T) => number; - - at: (index: number) => T | undefined; - first: () => T | undefined; - last: () => T | undefined; - - lower: (value: T) => T | undefined; - higher: (value: T) => T | undefined; - floor: (value: T) => T | undefined; - ceil: (value: T) => T | undefined; - - shift: () => T | undefined; - pop: (index?: number) => T | undefined; - - count: (value: T) => number; - - keys: () => IterableIterator; - values: () => IterableIterator; - rvalues: () => IterableIterator; - entries: () => IterableIterator<[number, T]>; - - readonly size: number; -} - -class TreapNode { - value: T; - count: number; - size: number; - priority: number; - left: TreapNode | null; - right: TreapNode | null; - - constructor(value: T) { - this.value = value; - this.count = 1; - this.size = 1; - this.priority = Math.random(); - this.left = null; - this.right = null; - } - - static getSize(node: TreapNode | null): number { - return node?.size ?? 0; - } - - static getFac(node: TreapNode | null): number { - return node?.priority ?? 0; - } - - pushUp(): void { - let tmp = this.count; - tmp += TreapNode.getSize(this.left); - tmp += TreapNode.getSize(this.right); - this.size = tmp; - } - - rotateRight(): TreapNode { - // eslint-disable-next-line @typescript-eslint/no-this-alias - let node: TreapNode = this; - const left = node.left; - node.left = left?.right ?? null; - left && (left.right = node); - left && (node = left); - node.right?.pushUp(); - node.pushUp(); - return node; - } - - rotateLeft(): TreapNode { - // eslint-disable-next-line @typescript-eslint/no-this-alias - let node: TreapNode = this; - const right = node.right; - node.right = right?.left ?? null; - right && (right.left = node); - right && (node = right); - node.left?.pushUp(); - node.pushUp(); - return node; - } -} - -class TreapMultiSet implements ITreapMultiSet { - private readonly root: TreapNode; - private readonly compareFn: CompareFunction; - private readonly leftBound: T; - private readonly rightBound: T; - - constructor(compareFn?: CompareFunction); - constructor(compareFn: CompareFunction, leftBound: T, rightBound: T); - constructor( - compareFn: CompareFunction = (a: any, b: any) => a - b, - leftBound: any = -Infinity, - rightBound: any = Infinity, - ) { - this.root = new TreapNode(rightBound); - this.root.priority = Infinity; - this.root.left = new TreapNode(leftBound); - this.root.left.priority = -Infinity; - this.root.pushUp(); - - this.leftBound = leftBound; - this.rightBound = rightBound; - this.compareFn = compareFn; - } - - get size(): number { - return this.root.size - 2; - } - - get height(): number { - const getHeight = (node: TreapNode | null): number => { - if (node == null) return 0; - return 1 + Math.max(getHeight(node.left), getHeight(node.right)); - }; - - return getHeight(this.root); - } - - /** - * - * @complexity `O(logn)` - * @description Returns true if value is a member. - */ - has(value: T): boolean { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): boolean => { - if (node == null) return false; - if (compare(node.value, value) === 0) return true; - if (compare(node.value, value) < 0) return dfs(node.right, value); - return dfs(node.left, value); - }; - - return dfs(this.root, value); - } - - /** - * - * @complexity `O(logn)` - * @description Add value to sorted set. - */ - add(...values: T[]): this { - const compare = this.compareFn; - const dfs = ( - node: TreapNode | null, - value: T, - parent: TreapNode, - direction: 'left' | 'right', - ): void => { - if (node == null) return; - if (compare(node.value, value) === 0) { - node.count++; - node.pushUp(); - } else if (compare(node.value, value) > 0) { - if (node.left) { - dfs(node.left, value, node, 'left'); - } else { - node.left = new TreapNode(value); - node.pushUp(); - } - - if (TreapNode.getFac(node.left) > node.priority) { - parent[direction] = node.rotateRight(); - } - } else if (compare(node.value, value) < 0) { - if (node.right) { - dfs(node.right, value, node, 'right'); - } else { - node.right = new TreapNode(value); - node.pushUp(); - } - - if (TreapNode.getFac(node.right) > node.priority) { - parent[direction] = node.rotateLeft(); - } - } - parent.pushUp(); - }; - - values.forEach(value => dfs(this.root.left, value, this.root, 'left')); - return this; - } - - /** - * - * @complexity `O(logn)` - * @description Remove value from sorted set if it is a member. - * If value is not a member, do nothing. - */ - delete(value: T): void { - const compare = this.compareFn; - const dfs = ( - node: TreapNode | null, - value: T, - parent: TreapNode, - direction: 'left' | 'right', - ): void => { - if (node == null) return; - - if (compare(node.value, value) === 0) { - if (node.count > 1) { - node.count--; - node?.pushUp(); - } else if (node.left == null && node.right == null) { - parent[direction] = null; - } else { - // 旋到根节点 - if ( - node.right == null || - TreapNode.getFac(node.left) > TreapNode.getFac(node.right) - ) { - parent[direction] = node.rotateRight(); - dfs(parent[direction]?.right ?? null, value, parent[direction]!, 'right'); - } else { - parent[direction] = node.rotateLeft(); - dfs(parent[direction]?.left ?? null, value, parent[direction]!, 'left'); - } - } - } else if (compare(node.value, value) > 0) { - dfs(node.left, value, node, 'left'); - } else if (compare(node.value, value) < 0) { - dfs(node.right, value, node, 'right'); - } - - parent?.pushUp(); - }; - - dfs(this.root.left, value, this.root, 'left'); - } - - /** - * - * @complexity `O(logn)` - * @description Returns an index to insert value in the sorted set. - * If the value is already present, the insertion point will be before (to the left of) any existing values. - */ - bisectLeft(value: T): number { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - return TreapNode.getSize(node.left); - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - - return dfs(this.root, value) - 1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns an index to insert value in the sorted set. - * If the value is already present, the insertion point will be before (to the right of) any existing values. - */ - bisectRight(value: T): number { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - return TreapNode.getSize(node.left) + node.count; - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - return dfs(this.root, value) - 1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns the index of the first occurrence of a value in the set, or -1 if it is not present. - */ - indexOf(value: T): number { - const compare = this.compareFn; - let isExist = false; - - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - isExist = true; - return TreapNode.getSize(node.left); - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - const res = dfs(this.root, value) - 1; - return isExist ? res : -1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns the index of the last occurrence of a value in the set, or -1 if it is not present. - */ - lastIndexOf(value: T): number { - const compare = this.compareFn; - let isExist = false; - - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - isExist = true; - return TreapNode.getSize(node.left) + node.count - 1; - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - - const res = dfs(this.root, value) - 1; - return isExist ? res : -1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns the item located at the specified index. - * @param index The zero-based index of the desired code unit. A negative index will count back from the last item. - */ - at(index: number): T | undefined { - if (index < 0) index += this.size; - if (index < 0 || index >= this.size) return undefined; - - const dfs = (node: TreapNode | null, rank: number): T | undefined => { - if (node == null) return undefined; - - if (TreapNode.getSize(node.left) >= rank) { - return dfs(node.left, rank); - } else if (TreapNode.getSize(node.left) + node.count >= rank) { - return node.value; - } else { - return dfs(node.right, rank - TreapNode.getSize(node.left) - node.count); - } - }; - - const res = dfs(this.root, index + 2); - return ([this.leftBound, this.rightBound] as any[]).includes(res) ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element less than `val`, return `undefined` if no such element found. - */ - lower(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) >= 0) return dfs(node.left, value); - - const tmp = dfs(node.right, value); - if (tmp == null || compare(node.value, tmp) > 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.leftBound ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element greater than `val`, return `undefined` if no such element found. - */ - higher(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) <= 0) return dfs(node.right, value); - - const tmp = dfs(node.left, value); - - if (tmp == null || compare(node.value, tmp) < 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.rightBound ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element less than or equal to `val`, return `undefined` if no such element found. - */ - floor(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) === 0) return node.value; - if (compare(node.value, value) >= 0) return dfs(node.left, value); - - const tmp = dfs(node.right, value); - if (tmp == null || compare(node.value, tmp) > 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.leftBound ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element greater than or equal to `val`, return `undefined` if no such element found. - */ - ceil(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) === 0) return node.value; - if (compare(node.value, value) <= 0) return dfs(node.right, value); - - const tmp = dfs(node.left, value); +#### Rust - if (tmp == null || compare(node.value, tmp) < 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.rightBound ? undefined : res; - } - - /** - * @complexity `O(logn)` - * @description - * Returns the last element from set. - * If the set is empty, undefined is returned. - */ - first(): T | undefined { - const iter = this.inOrder(); - iter.next(); - const res = iter.next().value; - return res === this.rightBound ? undefined : res; - } - - /** - * @complexity `O(logn)` - * @description - * Returns the last element from set. - * If the set is empty, undefined is returned . - */ - last(): T | undefined { - const iter = this.reverseInOrder(); - iter.next(); - const res = iter.next().value; - return res === this.leftBound ? undefined : res; - } - - /** - * @complexity `O(logn)` - * @description - * Removes the first element from an set and returns it. - * If the set is empty, undefined is returned and the set is not modified. - */ - shift(): T | undefined { - const first = this.first(); - if (first === undefined) return undefined; - this.delete(first); - return first; - } - - /** - * @complexity `O(logn)` - * @description - * Removes the last element from an set and returns it. - * If the set is empty, undefined is returned and the set is not modified. - */ - pop(index?: number): T | undefined { - if (index == null) { - const last = this.last(); - if (last === undefined) return undefined; - this.delete(last); - return last; - } - - const toDelete = this.at(index); - if (toDelete == null) return; - this.delete(toDelete); - return toDelete; - } - - /** - * - * @complexity `O(logn)` - * @description - * Returns number of occurrences of value in the sorted set. - */ - count(value: T): number { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - if (compare(node.value, value) === 0) return node.count; - if (compare(node.value, value) < 0) return dfs(node.right, value); - return dfs(node.left, value); - }; - - return dfs(this.root, value); - } - - *[Symbol.iterator](): Generator { - yield* this.values(); - } +```rust +use std::collections::{BTreeSet, VecDeque}; - /** - * @description - * Returns an iterable of keys in the set. - */ - *keys(): Generator { - yield* this.values(); - } - - /** - * @description - * Returns an iterable of values in the set. - */ - *values(): Generator { - const iter = this.inOrder(); - iter.next(); - const steps = this.size; - for (let _ = 0; _ < steps; _++) { - yield iter.next().value; - } - } +impl Solution { + pub fn min_reverse_operations(n: i32, p: i32, banned: Vec, k: i32) -> Vec { + let mut ans = vec![-1; n as usize]; + let mut ts = [BTreeSet::new(), BTreeSet::new()]; - /** - * @description - * Returns a generator for reversed order traversing the set. - */ - *rvalues(): Generator { - const iter = this.reverseInOrder(); - iter.next(); - const steps = this.size; - for (let _ = 0; _ < steps; _++) { - yield iter.next().value; + for i in 0..n { + ts[(i % 2) as usize].insert(i); } - } + ans[p as usize] = 0; + ts[(p % 2) as usize].remove(&p); - /** - * @description - * Returns an iterable of key, value pairs for every entry in the set. - */ - *entries(): IterableIterator<[number, T]> { - const iter = this.inOrder(); - iter.next(); - const steps = this.size; - for (let i = 0; i < steps; i++) { - yield [i, iter.next().value]; + for &b in &banned { + ts[(b % 2) as usize].remove(&b); } - } - private *inOrder(root: TreapNode | null = this.root): Generator { - if (root == null) return; - yield* this.inOrder(root.left); - const count = root.count; - for (let _ = 0; _ < count; _++) { - yield root.value; + ts[0].insert(n); + ts[1].insert(n); + let mut q = VecDeque::new(); + q.push_back(p); + + while let Some(i) = q.pop_front() { + let mi = (i - k + 1).max(k - i - 1); + let mx = (i + k - 1).min(2 * n - k - i - 1); + let s = &mut ts[(mi % 2) as usize]; + + while let Some(&j) = s.range(mi..=mx).next() { + q.push_back(j); + ans[j as usize] = ans[i as usize] + 1; + s.remove(&j); + } } - yield* this.inOrder(root.right); - } - private *reverseInOrder(root: TreapNode | null = this.root): Generator { - if (root == null) return; - yield* this.reverseInOrder(root.right); - const count = root.count; - for (let _ = 0; _ < count; _++) { - yield root.value; - } - yield* this.reverseInOrder(root.left); + ans } } ``` diff --git a/solution/2600-2699/2612.Minimum Reverse Operations/Solution.rs b/solution/2600-2699/2612.Minimum Reverse Operations/Solution.rs new file mode 100644 index 0000000000000..359d41e407ede --- /dev/null +++ b/solution/2600-2699/2612.Minimum Reverse Operations/Solution.rs @@ -0,0 +1,37 @@ +use std::collections::{BTreeSet, VecDeque}; + +impl Solution { + pub fn min_reverse_operations(n: i32, p: i32, banned: Vec, k: i32) -> Vec { + let mut ans = vec![-1; n as usize]; + let mut ts = [BTreeSet::new(), BTreeSet::new()]; + + for i in 0..n { + ts[(i % 2) as usize].insert(i); + } + ans[p as usize] = 0; + ts[(p % 2) as usize].remove(&p); + + for &b in &banned { + ts[(b % 2) as usize].remove(&b); + } + + ts[0].insert(n); + ts[1].insert(n); + let mut q = VecDeque::new(); + q.push_back(p); + + while let Some(i) = q.pop_front() { + let mi = (i - k + 1).max(k - i - 1); + let mx = (i + k - 1).min(2 * n - k - i - 1); + let s = &mut ts[(mi % 2) as usize]; + + while let Some(&j) = s.range(mi..=mx).next() { + q.push_back(j); + ans[j as usize] = ans[i as usize] + 1; + s.remove(&j); + } + } + + ans + } +} diff --git a/solution/2600-2699/2612.Minimum Reverse Operations/Solution.ts b/solution/2600-2699/2612.Minimum Reverse Operations/Solution.ts index 9bc9a36b42da1..f5dc9a3cdae78 100644 --- a/solution/2600-2699/2612.Minimum Reverse Operations/Solution.ts +++ b/solution/2600-2699/2612.Minimum Reverse Operations/Solution.ts @@ -1,6 +1,6 @@ function minReverseOperations(n: number, p: number, banned: number[], k: number): number[] { - const ans = new Array(n).fill(-1); - const ts = new Array(2).fill(0).map(() => new TreeSet()); + const ans: number[] = Array(n).fill(-1); + const ts = [new TreeSet(), new TreeSet()]; for (let i = 0; i < n; ++i) { ts[i % 2].add(i); } diff --git a/solution/2600-2699/2612.Minimum Reverse Operations/Solution2.ts b/solution/2600-2699/2612.Minimum Reverse Operations/Solution2.ts deleted file mode 100644 index aa507ef254aab..0000000000000 --- a/solution/2600-2699/2612.Minimum Reverse Operations/Solution2.ts +++ /dev/null @@ -1,648 +0,0 @@ -function minReverseOperations(n: number, p: number, banned: number[], k: number): number[] { - const ans = new Array(n).fill(-1); - const ts = new Array(2).fill(0).map(() => new TreapMultiSet()); - for (let i = 0; i < n; ++i) { - ts[i % 2].add(i); - } - ans[p] = 0; - ts[p % 2].delete(p); - for (const i of banned) { - ts[i % 2].delete(i); - } - ts[0].add(n); - ts[1].add(n); - let q = [p]; - while (q.length) { - const t: number[] = []; - for (const i of q) { - const mi = Math.max(i - k + 1, k - i - 1); - const mx = Math.min(i + k - 1, n * 2 - k - i - 1); - const s = ts[mi % 2]; - for (let j = s.ceil(mi)!; j <= mx; j = s.ceil(j)!) { - t.push(j); - ans[j] = ans[i] + 1; - s.delete(j); - } - } - q = t; - } - return ans; -} - -type CompareFunction = ( - a: T, - b: T, -) => R extends 'number' ? number : boolean; - -interface ITreapMultiSet extends Iterable { - add: (...value: T[]) => this; - has: (value: T) => boolean; - delete: (value: T) => void; - - bisectLeft: (value: T) => number; - bisectRight: (value: T) => number; - - indexOf: (value: T) => number; - lastIndexOf: (value: T) => number; - - at: (index: number) => T | undefined; - first: () => T | undefined; - last: () => T | undefined; - - lower: (value: T) => T | undefined; - higher: (value: T) => T | undefined; - floor: (value: T) => T | undefined; - ceil: (value: T) => T | undefined; - - shift: () => T | undefined; - pop: (index?: number) => T | undefined; - - count: (value: T) => number; - - keys: () => IterableIterator; - values: () => IterableIterator; - rvalues: () => IterableIterator; - entries: () => IterableIterator<[number, T]>; - - readonly size: number; -} - -class TreapNode { - value: T; - count: number; - size: number; - priority: number; - left: TreapNode | null; - right: TreapNode | null; - - constructor(value: T) { - this.value = value; - this.count = 1; - this.size = 1; - this.priority = Math.random(); - this.left = null; - this.right = null; - } - - static getSize(node: TreapNode | null): number { - return node?.size ?? 0; - } - - static getFac(node: TreapNode | null): number { - return node?.priority ?? 0; - } - - pushUp(): void { - let tmp = this.count; - tmp += TreapNode.getSize(this.left); - tmp += TreapNode.getSize(this.right); - this.size = tmp; - } - - rotateRight(): TreapNode { - // eslint-disable-next-line @typescript-eslint/no-this-alias - let node: TreapNode = this; - const left = node.left; - node.left = left?.right ?? null; - left && (left.right = node); - left && (node = left); - node.right?.pushUp(); - node.pushUp(); - return node; - } - - rotateLeft(): TreapNode { - // eslint-disable-next-line @typescript-eslint/no-this-alias - let node: TreapNode = this; - const right = node.right; - node.right = right?.left ?? null; - right && (right.left = node); - right && (node = right); - node.left?.pushUp(); - node.pushUp(); - return node; - } -} - -class TreapMultiSet implements ITreapMultiSet { - private readonly root: TreapNode; - private readonly compareFn: CompareFunction; - private readonly leftBound: T; - private readonly rightBound: T; - - constructor(compareFn?: CompareFunction); - constructor(compareFn: CompareFunction, leftBound: T, rightBound: T); - constructor( - compareFn: CompareFunction = (a: any, b: any) => a - b, - leftBound: any = -Infinity, - rightBound: any = Infinity, - ) { - this.root = new TreapNode(rightBound); - this.root.priority = Infinity; - this.root.left = new TreapNode(leftBound); - this.root.left.priority = -Infinity; - this.root.pushUp(); - - this.leftBound = leftBound; - this.rightBound = rightBound; - this.compareFn = compareFn; - } - - get size(): number { - return this.root.size - 2; - } - - get height(): number { - const getHeight = (node: TreapNode | null): number => { - if (node == null) return 0; - return 1 + Math.max(getHeight(node.left), getHeight(node.right)); - }; - - return getHeight(this.root); - } - - /** - * - * @complexity `O(logn)` - * @description Returns true if value is a member. - */ - has(value: T): boolean { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): boolean => { - if (node == null) return false; - if (compare(node.value, value) === 0) return true; - if (compare(node.value, value) < 0) return dfs(node.right, value); - return dfs(node.left, value); - }; - - return dfs(this.root, value); - } - - /** - * - * @complexity `O(logn)` - * @description Add value to sorted set. - */ - add(...values: T[]): this { - const compare = this.compareFn; - const dfs = ( - node: TreapNode | null, - value: T, - parent: TreapNode, - direction: 'left' | 'right', - ): void => { - if (node == null) return; - if (compare(node.value, value) === 0) { - node.count++; - node.pushUp(); - } else if (compare(node.value, value) > 0) { - if (node.left) { - dfs(node.left, value, node, 'left'); - } else { - node.left = new TreapNode(value); - node.pushUp(); - } - - if (TreapNode.getFac(node.left) > node.priority) { - parent[direction] = node.rotateRight(); - } - } else if (compare(node.value, value) < 0) { - if (node.right) { - dfs(node.right, value, node, 'right'); - } else { - node.right = new TreapNode(value); - node.pushUp(); - } - - if (TreapNode.getFac(node.right) > node.priority) { - parent[direction] = node.rotateLeft(); - } - } - parent.pushUp(); - }; - - values.forEach(value => dfs(this.root.left, value, this.root, 'left')); - return this; - } - - /** - * - * @complexity `O(logn)` - * @description Remove value from sorted set if it is a member. - * If value is not a member, do nothing. - */ - delete(value: T): void { - const compare = this.compareFn; - const dfs = ( - node: TreapNode | null, - value: T, - parent: TreapNode, - direction: 'left' | 'right', - ): void => { - if (node == null) return; - - if (compare(node.value, value) === 0) { - if (node.count > 1) { - node.count--; - node?.pushUp(); - } else if (node.left == null && node.right == null) { - parent[direction] = null; - } else { - // 旋到根节点 - if ( - node.right == null || - TreapNode.getFac(node.left) > TreapNode.getFac(node.right) - ) { - parent[direction] = node.rotateRight(); - dfs(parent[direction]?.right ?? null, value, parent[direction]!, 'right'); - } else { - parent[direction] = node.rotateLeft(); - dfs(parent[direction]?.left ?? null, value, parent[direction]!, 'left'); - } - } - } else if (compare(node.value, value) > 0) { - dfs(node.left, value, node, 'left'); - } else if (compare(node.value, value) < 0) { - dfs(node.right, value, node, 'right'); - } - - parent?.pushUp(); - }; - - dfs(this.root.left, value, this.root, 'left'); - } - - /** - * - * @complexity `O(logn)` - * @description Returns an index to insert value in the sorted set. - * If the value is already present, the insertion point will be before (to the left of) any existing values. - */ - bisectLeft(value: T): number { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - return TreapNode.getSize(node.left); - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - - return dfs(this.root, value) - 1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns an index to insert value in the sorted set. - * If the value is already present, the insertion point will be before (to the right of) any existing values. - */ - bisectRight(value: T): number { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - return TreapNode.getSize(node.left) + node.count; - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - return dfs(this.root, value) - 1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns the index of the first occurrence of a value in the set, or -1 if it is not present. - */ - indexOf(value: T): number { - const compare = this.compareFn; - let isExist = false; - - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - isExist = true; - return TreapNode.getSize(node.left); - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - const res = dfs(this.root, value) - 1; - return isExist ? res : -1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns the index of the last occurrence of a value in the set, or -1 if it is not present. - */ - lastIndexOf(value: T): number { - const compare = this.compareFn; - let isExist = false; - - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - - if (compare(node.value, value) === 0) { - isExist = true; - return TreapNode.getSize(node.left) + node.count - 1; - } else if (compare(node.value, value) > 0) { - return dfs(node.left, value); - } else if (compare(node.value, value) < 0) { - return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count; - } - - return 0; - }; - - const res = dfs(this.root, value) - 1; - return isExist ? res : -1; - } - - /** - * - * @complexity `O(logn)` - * @description Returns the item located at the specified index. - * @param index The zero-based index of the desired code unit. A negative index will count back from the last item. - */ - at(index: number): T | undefined { - if (index < 0) index += this.size; - if (index < 0 || index >= this.size) return undefined; - - const dfs = (node: TreapNode | null, rank: number): T | undefined => { - if (node == null) return undefined; - - if (TreapNode.getSize(node.left) >= rank) { - return dfs(node.left, rank); - } else if (TreapNode.getSize(node.left) + node.count >= rank) { - return node.value; - } else { - return dfs(node.right, rank - TreapNode.getSize(node.left) - node.count); - } - }; - - const res = dfs(this.root, index + 2); - return ([this.leftBound, this.rightBound] as any[]).includes(res) ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element less than `val`, return `undefined` if no such element found. - */ - lower(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) >= 0) return dfs(node.left, value); - - const tmp = dfs(node.right, value); - if (tmp == null || compare(node.value, tmp) > 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.leftBound ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element greater than `val`, return `undefined` if no such element found. - */ - higher(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) <= 0) return dfs(node.right, value); - - const tmp = dfs(node.left, value); - - if (tmp == null || compare(node.value, tmp) < 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.rightBound ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element less than or equal to `val`, return `undefined` if no such element found. - */ - floor(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) === 0) return node.value; - if (compare(node.value, value) >= 0) return dfs(node.left, value); - - const tmp = dfs(node.right, value); - if (tmp == null || compare(node.value, tmp) > 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.leftBound ? undefined : res; - } - - /** - * - * @complexity `O(logn)` - * @description Find and return the element greater than or equal to `val`, return `undefined` if no such element found. - */ - ceil(value: T): T | undefined { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): T | undefined => { - if (node == null) return undefined; - if (compare(node.value, value) === 0) return node.value; - if (compare(node.value, value) <= 0) return dfs(node.right, value); - - const tmp = dfs(node.left, value); - - if (tmp == null || compare(node.value, tmp) < 0) { - return node.value; - } else { - return tmp; - } - }; - - const res = dfs(this.root, value) as any; - return res === this.rightBound ? undefined : res; - } - - /** - * @complexity `O(logn)` - * @description - * Returns the last element from set. - * If the set is empty, undefined is returned. - */ - first(): T | undefined { - const iter = this.inOrder(); - iter.next(); - const res = iter.next().value; - return res === this.rightBound ? undefined : res; - } - - /** - * @complexity `O(logn)` - * @description - * Returns the last element from set. - * If the set is empty, undefined is returned . - */ - last(): T | undefined { - const iter = this.reverseInOrder(); - iter.next(); - const res = iter.next().value; - return res === this.leftBound ? undefined : res; - } - - /** - * @complexity `O(logn)` - * @description - * Removes the first element from an set and returns it. - * If the set is empty, undefined is returned and the set is not modified. - */ - shift(): T | undefined { - const first = this.first(); - if (first === undefined) return undefined; - this.delete(first); - return first; - } - - /** - * @complexity `O(logn)` - * @description - * Removes the last element from an set and returns it. - * If the set is empty, undefined is returned and the set is not modified. - */ - pop(index?: number): T | undefined { - if (index == null) { - const last = this.last(); - if (last === undefined) return undefined; - this.delete(last); - return last; - } - - const toDelete = this.at(index); - if (toDelete == null) return; - this.delete(toDelete); - return toDelete; - } - - /** - * - * @complexity `O(logn)` - * @description - * Returns number of occurrences of value in the sorted set. - */ - count(value: T): number { - const compare = this.compareFn; - const dfs = (node: TreapNode | null, value: T): number => { - if (node == null) return 0; - if (compare(node.value, value) === 0) return node.count; - if (compare(node.value, value) < 0) return dfs(node.right, value); - return dfs(node.left, value); - }; - - return dfs(this.root, value); - } - - *[Symbol.iterator](): Generator { - yield* this.values(); - } - - /** - * @description - * Returns an iterable of keys in the set. - */ - *keys(): Generator { - yield* this.values(); - } - - /** - * @description - * Returns an iterable of values in the set. - */ - *values(): Generator { - const iter = this.inOrder(); - iter.next(); - const steps = this.size; - for (let _ = 0; _ < steps; _++) { - yield iter.next().value; - } - } - - /** - * @description - * Returns a generator for reversed order traversing the set. - */ - *rvalues(): Generator { - const iter = this.reverseInOrder(); - iter.next(); - const steps = this.size; - for (let _ = 0; _ < steps; _++) { - yield iter.next().value; - } - } - - /** - * @description - * Returns an iterable of key, value pairs for every entry in the set. - */ - *entries(): IterableIterator<[number, T]> { - const iter = this.inOrder(); - iter.next(); - const steps = this.size; - for (let i = 0; i < steps; i++) { - yield [i, iter.next().value]; - } - } - - private *inOrder(root: TreapNode | null = this.root): Generator { - if (root == null) return; - yield* this.inOrder(root.left); - const count = root.count; - for (let _ = 0; _ < count; _++) { - yield root.value; - } - yield* this.inOrder(root.right); - } - - private *reverseInOrder(root: TreapNode | null = this.root): Generator { - if (root == null) return; - yield* this.reverseInOrder(root.right); - const count = root.count; - for (let _ = 0; _ < count; _++) { - yield root.value; - } - yield* this.reverseInOrder(root.left); - } -}