请你实现三个 API append
,addAll
和 multAll
来实现奇妙序列。
请实现 Fancy
类 :
Fancy()
初始化一个空序列对象。void append(val)
将整数val
添加在序列末尾。void addAll(inc)
将所有序列中的现有数值都增加inc
。void multAll(m)
将序列中的所有现有数值都乘以整数m
。int getIndex(idx)
得到下标为idx
处的数值(下标从 0 开始),并将结果对109 + 7
取余。如果下标大于等于序列的长度,请返回-1
。
示例:
输入: ["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
提示:
1 <= val, inc, m <= 100
0 <= idx <= 105
- 总共最多会有
105
次对append
,addAll
,multAll
和getIndex
的调用。
方法一:线段树
线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 log(width)
。更新某个元素的值,只需要更新 log(width)
个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用懒标记保证效率。
- 线段树的每个节点代表一个区间;
- 线段树具有唯一的根节点,代表的区间是整个统计范围,如
[1, N]
; - 线段树的每个叶子节点代表一个长度为 1 的元区间
[x, x]
; - 对于每个内部节点
[l, r]
,它的左儿子是[l, mid]
,右儿子是[mid + 1, r]
, 其中mid = ⌊(l + r) / 2⌋
(即向下取整)。
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)
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);
*/
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);
*/