diff --git "a/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/README.md" "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/README.md" index d6f58bdfd0998..e6afadc06a0fd 100644 --- "a/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/README.md" +++ "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/README.md" @@ -311,4 +311,823 @@ func (h *hp) Pop() any { + + +### 方法二:有序集合 + +与方法一类似,我们可以用两个有序集合 $\textit{l}$ 和 $\textit{r}$ 分别维护前缀数组较小的一半元素和较大的一半元素。 + +具体地,我们创建两个有序集合 $\textit{l}$ 和 $\textit{r}$,其中:$\textit{l}$ 存放较小的一半元素,$\textit{r}$ 存放较大的一半元素。同时,我们维护两个变量 $\textit{s}$ 和 $\textit{t}$ 分别记录 $\textit{l}$ 和 $\textit{r}$ 的元素和。 + +添加元素时,先放入 $\textit{r}$,然后将 $\textit{r}$ 的最小元素弹出并放入 $\textit{l}$(使得 $\textit{l}$ 的元素个数多 $1$);若 $\textit{l}$ 元素个数与 $\textit{r}$ 元素个数差超过 $1$,则将 $\textit{l}$ 的最大元素弹出放入 $\textit{r}$。过程中,用两个变量 $\textit{s}$ 和 $\textit{t}$ 分别记录两个集合的元素和。那么,此时的中位数为 $\textit{l}$ 的最大元素,最小操作次数为中位数乘以 $\textit{l}$ 的元素个数减去 $\textit{s}$ 再加上 $\textit{t}$ 减去中位数乘以 $\textit{r}$ 的元素个数。 + +时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 为数组长度。 + + + +#### Python3 + +```python +from sortedcontainers import SortedList + + +class Solution: + def numsGame(self, nums: List[int]) -> List[int]: + l = SortedList() + r = SortedList() + s = t = 0 + mod = 10**9 + 7 + ans = [] + for i, x in enumerate(nums): + x -= i + r.add(x) + t += x + x = r.pop(0) + t -= x + l.add(x) + s += x + while len(l) - len(r) > 1: + x = l.pop() + s -= x + r.add(x) + t += x + v = len(l) * l[-1] - s + t - len(r) * l[-1] + ans.append(v % mod) + return ans +``` + +#### Java + +```java +class Solution { + public int[] numsGame(int[] nums) { + TreeMap l = new TreeMap<>(); + TreeMap r = new TreeMap<>(); + int n = nums.length; + int[] ans = new int[n]; + final int mod = (int) 1e9 + 7; + long s = 0, t = 0; + int lSize = 0, rSize = 0; + for (int i = 0; i < n; ++i) { + int x = nums[i] - i; + r.merge(x, 1, Integer::sum); + t += x; + x = r.firstKey(); + if (r.merge(x, -1, Integer::sum) == 0) { + r.remove(x); + } + t -= x; + l.merge(x, 1, Integer::sum); + s += x; + ++lSize; + while (lSize - rSize > 1) { + x = l.lastKey(); + if (l.merge(x, -1, Integer::sum) == 0) { + l.remove(x); + } + s -= x; + --lSize; + r.merge(x, 1, Integer::sum); + t += x; + ++rSize; + } + long mid = l.lastKey(); + ans[i] = (int) ((mid * lSize - s + t - mid * rSize) % mod); + } + return ans; + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + vector numsGame(vector& nums) { + multiset l, r; + int n = nums.size(); + vector ans(n); + const int mod = 1e9 + 7; + long long s = 0, t = 0; + for (int i = 0; i < n; ++i) { + int x = nums[i] - i; + r.insert(x); + t += x; + x = *r.begin(); + r.erase(r.begin()); + t -= x; + l.insert(x); + s += x; + while (l.size() - r.size() > 1) { + x = *l.rbegin(); + l.erase(l.find(x)); + s -= x; + r.insert(x); + t += x; + } + long long mid = *l.rbegin(); + ans[i] = (mid * l.size() - s + t - mid * r.size()) % mod; + } + return ans; + } +}; +``` + +#### Go + +```go +func numsGame(nums []int) (ans []int) { + l := redblacktree.New[int, int]() + r := redblacktree.New[int, int]() + merge := func(st *redblacktree.Tree[int, int], x, v int) { + c, _ := st.Get(x) + if c+v == 0 { + st.Remove(x) + } else { + st.Put(x, c+v) + } + } + s, t := 0, 0 + lSize, rSize := 0, 0 + const mod int = 1e9 + 7 + for i, x := range nums { + x -= i + merge(r, x, 1) + t += x + x = r.Left().Key + merge(r, x, -1) + t -= x + merge(l, x, 1) + s += x + lSize++ + for lSize-rSize > 1 { + x = l.Right().Key + merge(l, x, -1) + s -= x + lSize-- + merge(r, x, 1) + t += x + rSize++ + } + mid := l.Right().Key + v := (mid*lSize%mod - s + t - mid*rSize%mod) % mod + ans = append(ans, v) + } + return +} +``` + +#### TypeScript + +```ts +function numsGame(nums: number[]): number[] { + const l = new TreapMultiSet((a, b) => a - b); + const r = new TreapMultiSet((a, b) => a - b); + let [s, t] = [0, 0]; + const ans: number[] = []; + const mod = 1e9 + 7; + for (let i = 0; i < nums.length; ++i) { + let x = nums[i] - i; + r.add(x); + t += x; + x = r.shift()!; + t -= x; + l.add(x); + s += x; + while (l.size - r.size > 1) { + x = l.pop()!; + s -= x; + r.add(x); + t += x; + } + const mid = l.last()!; + ans.push((((mid * l.size) % mod) - s + t - ((mid * r.size) % mod) + mod) % mod); + } + 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); + } +} +``` + + + + + diff --git "a/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.cpp" "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.cpp" new file mode 100644 index 0000000000000..39a29f121f2fb --- /dev/null +++ "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.cpp" @@ -0,0 +1,30 @@ +class Solution { +public: + vector numsGame(vector& nums) { + multiset l, r; + int n = nums.size(); + vector ans(n); + const int mod = 1e9 + 7; + long long s = 0, t = 0; + for (int i = 0; i < n; ++i) { + int x = nums[i] - i; + r.insert(x); + t += x; + x = *r.begin(); + r.erase(r.begin()); + t -= x; + l.insert(x); + s += x; + while (l.size() - r.size() > 1) { + x = *l.rbegin(); + l.erase(l.find(x)); + s -= x; + r.insert(x); + t += x; + } + long long mid = *l.rbegin(); + ans[i] = (mid * l.size() - s + t - mid * r.size()) % mod; + } + return ans; + } +}; diff --git "a/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.go" "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.go" new file mode 100644 index 0000000000000..415d4ea87d1e3 --- /dev/null +++ "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.go" @@ -0,0 +1,39 @@ +func numsGame(nums []int) (ans []int) { + l := redblacktree.New[int, int]() + r := redblacktree.New[int, int]() + merge := func(st *redblacktree.Tree[int, int], x, v int) { + c, _ := st.Get(x) + if c+v == 0 { + st.Remove(x) + } else { + st.Put(x, c+v) + } + } + s, t := 0, 0 + lSize, rSize := 0, 0 + const mod int = 1e9 + 7 + for i, x := range nums { + x -= i + merge(r, x, 1) + t += x + x = r.Left().Key + merge(r, x, -1) + t -= x + merge(l, x, 1) + s += x + lSize++ + for lSize-rSize > 1 { + x = l.Right().Key + merge(l, x, -1) + s -= x + lSize-- + merge(r, x, 1) + t += x + rSize++ + } + mid := l.Right().Key + v := (mid*lSize%mod - s + t - mid*rSize%mod) % mod + ans = append(ans, v) + } + return +} diff --git "a/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.java" "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.java" new file mode 100644 index 0000000000000..1a8dae9899c87 --- /dev/null +++ "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.java" @@ -0,0 +1,38 @@ +class Solution { + public int[] numsGame(int[] nums) { + TreeMap l = new TreeMap<>(); + TreeMap r = new TreeMap<>(); + int n = nums.length; + int[] ans = new int[n]; + final int mod = (int) 1e9 + 7; + long s = 0, t = 0; + int lSize = 0, rSize = 0; + for (int i = 0; i < n; ++i) { + int x = nums[i] - i; + r.merge(x, 1, Integer::sum); + t += x; + x = r.firstKey(); + if (r.merge(x, -1, Integer::sum) == 0) { + r.remove(x); + } + t -= x; + l.merge(x, 1, Integer::sum); + s += x; + ++lSize; + while (lSize - rSize > 1) { + x = l.lastKey(); + if (l.merge(x, -1, Integer::sum) == 0) { + l.remove(x); + } + s -= x; + --lSize; + r.merge(x, 1, Integer::sum); + t += x; + ++rSize; + } + long mid = l.lastKey(); + ans[i] = (int) ((mid * lSize - s + t - mid * rSize) % mod); + } + return ans; + } +} diff --git "a/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.py" "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.py" new file mode 100644 index 0000000000000..aad34c9845934 --- /dev/null +++ "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.py" @@ -0,0 +1,26 @@ +from sortedcontainers import SortedList + + +class Solution: + def numsGame(self, nums: List[int]) -> List[int]: + l = SortedList() + r = SortedList() + s = t = 0 + mod = 10**9 + 7 + ans = [] + for i, x in enumerate(nums): + x -= i + r.add(x) + t += x + x = r.pop(0) + t -= x + l.add(x) + s += x + while len(l) - len(r) > 1: + x = l.pop() + s -= x + r.add(x) + t += x + v = len(l) * l[-1] - s + t - len(r) * l[-1] + ans.append(v % mod) + return ans diff --git "a/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.ts" "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.ts" new file mode 100644 index 0000000000000..1b37b813da445 --- /dev/null +++ "b/lcp/LCP 24. \346\225\260\345\255\227\346\270\270\346\210\217/Solution2.ts" @@ -0,0 +1,643 @@ +function numsGame(nums: number[]): number[] { + const l = new TreapMultiSet((a, b) => a - b); + const r = new TreapMultiSet((a, b) => a - b); + let [s, t] = [0, 0]; + const ans: number[] = []; + const mod = 1e9 + 7; + for (let i = 0; i < nums.length; ++i) { + let x = nums[i] - i; + r.add(x); + t += x; + x = r.shift()!; + t -= x; + l.add(x); + s += x; + while (l.size - r.size > 1) { + x = l.pop()!; + s -= x; + r.add(x); + t += x; + } + const mid = l.last()!; + ans.push((((mid * l.size) % mod) - s + t - ((mid * r.size) % mod) + mod) % mod); + } + 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); + } +}