--- comments: true difficulty: 困难 edit_url: https://github.com/doocs/leetcode/edit/main/solution/1600-1699/1622.Fancy%20Sequence/README.md rating: 2476 source: 第 37 场双周赛 Q4 tags: - 设计 - 线段树 - 数学 --- # [1622. 奇妙序列](https://leetcode.cn/problems/fancy-sequence) [English Version](/solution/1600-1699/1622.Fancy%20Sequence/README_EN.md) ## 题目描述

请你实现三个 API appendaddAll 和 multAll 来实现奇妙序列。

请实现 Fancy 类 :

 

示例:

输入:
["Fancy", "append", "addAll", "append", "multAll", "getIndex", "addAll", "append", "multAll", "getIndex", "getIndex", "getIndex"]
[[], [2], [3], [7], [2], [0], [3], [10], [2], [0], [1], [2]]
输出:
[null, null, null, null, null, 10, null, null, null, 26, 34, 20]

解释:
Fancy fancy = new Fancy();
fancy.append(2);   // 奇妙序列:[2]
fancy.addAll(3);   // 奇妙序列:[2+3] -> [5]
fancy.append(7);   // 奇妙序列:[5, 7]
fancy.multAll(2);  // 奇妙序列:[5*2, 7*2] -> [10, 14]
fancy.getIndex(0); // 返回 10
fancy.addAll(3);   // 奇妙序列:[10+3, 14+3] -> [13, 17]
fancy.append(10);  // 奇妙序列:[13, 17, 10]
fancy.multAll(2);  // 奇妙序列:[13*2, 17*2, 10*2] -> [26, 34, 20]
fancy.getIndex(0); // 返回 26
fancy.getIndex(1); // 返回 34
fancy.getIndex(2); // 返回 20

 

提示:

## 解法 ### 方法一:线段树 线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 `log(width)`。更新某个元素的值,只需要更新 `log(width)` 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用**懒标记**保证效率。 - 线段树的每个节点代表一个区间; - 线段树具有唯一的根节点,代表的区间是整个统计范围,如 `[1, N]`; - 线段树的每个叶子节点代表一个长度为 1 的元区间 `[x, x]`; - 对于每个内部节点 `[l, r]`,它的左儿子是 `[l, mid]`,右儿子是 `[mid + 1, r]`, 其中 `mid = ⌊(l + r) / 2⌋` (即向下取整)。 #### Python3 ```python MOD = int(1e9 + 7) class Node: def __init__(self, l, r): self.left = None self.right = None self.l = l self.r = r self.mid = (l + r) >> 1 self.v = 0 self.add = 0 self.mul = 1 class SegmentTree: def __init__(self): self.root = Node(1, int(1e5 + 1)) def modifyAdd(self, l, r, inc, node=None): if l > r: return if node is None: node = self.root if node.l >= l and node.r <= r: node.v = (node.v + (node.r - node.l + 1) * inc) % MOD node.add += inc return self.pushdown(node) if l <= node.mid: self.modifyAdd(l, r, inc, node.left) if r > node.mid: self.modifyAdd(l, r, inc, node.right) self.pushup(node) def modifyMul(self, l, r, m, node=None): if l > r: return if node is None: node = self.root if node.l >= l and node.r <= r: node.v = (node.v * m) % MOD node.add = (node.add * m) % MOD node.mul = (node.mul * m) % MOD return self.pushdown(node) if l <= node.mid: self.modifyMul(l, r, m, node.left) if r > node.mid: self.modifyMul(l, r, m, node.right) self.pushup(node) def query(self, l, r, node=None): if l > r: return 0 if node is None: node = self.root if node.l >= l and node.r <= r: return node.v self.pushdown(node) v = 0 if l <= node.mid: v = (v + self.query(l, r, node.left)) % MOD if r > node.mid: v = (v + self.query(l, r, node.right)) % MOD return v def pushup(self, node): node.v = (node.left.v + node.right.v) % MOD def pushdown(self, node): if node.left is None: node.left = Node(node.l, node.mid) if node.right is None: node.right = Node(node.mid + 1, node.r) left, right = node.left, node.right if node.add != 0 or node.mul != 1: left.v = (left.v * node.mul + (left.r - left.l + 1) * node.add) % MOD right.v = (right.v * node.mul + (right.r - right.l + 1) * node.add) % MOD left.add = (left.add * node.mul + node.add) % MOD right.add = (right.add * node.mul + node.add) % MOD left.mul = (left.mul * node.mul) % MOD right.mul = (right.mul * node.mul) % MOD node.add = 0 node.mul = 1 class Fancy: def __init__(self): self.n = 0 self.tree = SegmentTree() def append(self, val: int) -> None: self.n += 1 self.tree.modifyAdd(self.n, self.n, val) def addAll(self, inc: int) -> None: self.tree.modifyAdd(1, self.n, inc) def multAll(self, m: int) -> None: self.tree.modifyMul(1, self.n, m) def getIndex(self, idx: int) -> int: return -1 if idx >= self.n else self.tree.query(idx + 1, idx + 1) # Your Fancy object will be instantiated and called as such: # obj = Fancy() # obj.append(val) # obj.addAll(inc) # obj.multAll(m) # param_4 = obj.getIndex(idx) ``` #### Java ```java class Node { Node left; Node right; int l; int r; int mid; long v; long add; long mul = 1; public Node(int l, int r) { this.l = l; this.r = r; this.mid = (l + r) >> 1; } } class SegmentTree { private Node root = new Node(1, (int) 1e5 + 1); private static final int MOD = (int) 1e9 + 7; public SegmentTree() { } public void modifyAdd(int l, int r, int inc) { modifyAdd(l, r, inc, root); } public void modifyAdd(int l, int r, int inc, Node node) { if (l > r) { return; } if (node.l >= l && node.r <= r) { node.v = (node.v + (node.r - node.l + 1) * inc) % MOD; node.add = (node.add + inc) % MOD; return; } pushdown(node); if (l <= node.mid) { modifyAdd(l, r, inc, node.left); } if (r > node.mid) { modifyAdd(l, r, inc, node.right); } pushup(node); } public void modifyMul(int l, int r, int m) { modifyMul(l, r, m, root); } public void modifyMul(int l, int r, int m, Node node) { if (l > r) { return; } if (node.l >= l && node.r <= r) { node.v = (node.v * m) % MOD; node.add = (node.add * m) % MOD; node.mul = (node.mul * m) % MOD; return; } pushdown(node); if (l <= node.mid) { modifyMul(l, r, m, node.left); } if (r > node.mid) { modifyMul(l, r, m, node.right); } pushup(node); } public int query(int l, int r) { return query(l, r, root); } public int query(int l, int r, Node node) { if (l > r) { return 0; } if (node.l >= l && node.r <= r) { return (int) node.v; } pushdown(node); int v = 0; if (l <= node.mid) { v = (v + query(l, r, node.left)) % MOD; } if (r > node.mid) { v = (v + query(l, r, node.right)) % MOD; } return v; } public void pushup(Node node) { node.v = (node.left.v + node.right.v) % MOD; } public void pushdown(Node node) { if (node.left == null) { node.left = new Node(node.l, node.mid); } if (node.right == null) { node.right = new Node(node.mid + 1, node.r); } if (node.add != 0 || node.mul != 1) { Node left = node.left, right = node.right; left.v = (left.v * node.mul + (left.r - left.l + 1) * node.add) % MOD; right.v = (right.v * node.mul + (right.r - right.l + 1) * node.add) % MOD; left.add = (left.add * node.mul + node.add) % MOD; right.add = (right.add * node.mul + node.add) % MOD; left.mul = (left.mul * node.mul) % MOD; right.mul = (right.mul * node.mul) % MOD; node.add = 0; node.mul = 1; } } } class Fancy { private int n; private SegmentTree tree = new SegmentTree(); public Fancy() { } public void append(int val) { ++n; tree.modifyAdd(n, n, val); } public void addAll(int inc) { tree.modifyAdd(1, n, inc); } public void multAll(int m) { tree.modifyMul(1, n, m); } public int getIndex(int idx) { return idx >= n ? -1 : tree.query(idx + 1, idx + 1); } } /** * Your Fancy object will be instantiated and called as such: * Fancy obj = new Fancy(); * obj.append(val); * obj.addAll(inc); * obj.multAll(m); * int param_4 = obj.getIndex(idx); */ ``` #### C++ ```cpp const int MOD = 1e9 + 7; class Node { public: Node* left; Node* right; int l; int r; int mid; long long v; long long add; long long mul; Node(int l, int r) { this->l = l; this->r = r; this->mid = (l + r) >> 1; this->left = this->right = nullptr; v = add = 0; mul = 1; } }; class SegmentTree { private: Node* root; public: SegmentTree() { root = new Node(1, 1e5 + 1); } void modifyAdd(int l, int r, int inc) { modifyAdd(l, r, inc, root); } void modifyAdd(int l, int r, int inc, Node* node) { if (l > r) return; if (node->l >= l && node->r <= r) { node->v = (node->v + (node->r - node->l + 1) * inc) % MOD; node->add = (node->add + inc) % MOD; return; } pushdown(node); if (l <= node->mid) modifyAdd(l, r, inc, node->left); if (r > node->mid) modifyAdd(l, r, inc, node->right); pushup(node); } void modifyMul(int l, int r, int m) { modifyMul(l, r, m, root); } void modifyMul(int l, int r, int m, Node* node) { if (l > r) return; if (node->l >= l && node->r <= r) { node->v = (node->v * m) % MOD; node->add = (node->add * m) % MOD; node->mul = (node->mul * m) % MOD; return; } pushdown(node); if (l <= node->mid) modifyMul(l, r, m, node->left); if (r > node->mid) modifyMul(l, r, m, node->right); pushup(node); } int query(int l, int r) { return query(l, r, root); } int query(int l, int r, Node* node) { if (l > r) return 0; if (node->l >= l && node->r <= r) return node->v; pushdown(node); int v = 0; if (l <= node->mid) v = (v + query(l, r, node->left)) % MOD; if (r > node->mid) v = (v + query(l, r, node->right)) % MOD; return v; } void pushup(Node* node) { node->v = (node->left->v + node->right->v) % MOD; } void pushdown(Node* node) { if (!node->left) node->left = new Node(node->l, node->mid); if (!node->right) node->right = new Node(node->mid + 1, node->r); if (node->add || node->mul != 1) { long add = node->add, mul = node->mul; Node* left = node->left; Node* right = node->right; left->v = (left->v * mul + (left->r - left->l + 1) * add) % MOD; right->v = (right->v * mul + (right->r - right->l + 1) * add) % MOD; left->add = (left->add * mul + add) % MOD; right->add = (right->add * mul + add) % MOD; left->mul = (left->mul * mul) % MOD; right->mul = (right->mul * mul) % MOD; node->add = 0; node->mul = 1; } } }; class Fancy { public: int n; SegmentTree* tree; Fancy() { n = 0; tree = new SegmentTree(); } void append(int val) { ++n; tree->modifyAdd(n, n, val); } void addAll(int inc) { tree->modifyAdd(1, n, inc); } void multAll(int m) { tree->modifyMul(1, n, m); } int getIndex(int idx) { return idx >= n ? -1 : tree->query(idx + 1, idx + 1); } }; /** * Your Fancy object will be instantiated and called as such: * Fancy* obj = new Fancy(); * obj->append(val); * obj->addAll(inc); * obj->multAll(m); * int param_4 = obj->getIndex(idx); */ ```