/** * Persistent Segment Tree (with lzay propagation) * finds the sum of the elements in an interval in a specified time since the start * adds a given value to the elements from an interval at a specified time since the start * thus we need to keep a version of all states of the tree but store only the different parts * to save memory and time * O(n) to build * O(log n) for sum * O(log n) for update * each update adds O(log n) additional memory */ #include #define endl '\n' using namespace std; const int MAX_SIZE = 1 << 19; struct Node { int from, to; int carry, val; Node *left, *right; } *root[MAX_SIZE]; int nums[MAX_SIZE]; // a normal build function Node* build(Node *node, int from, int to) { node->from = from; node->to = to; node->carry = 0; if(from == to) { node->val = nums[from]; return node; } int mid = (from + to) >> 1; node->left = new Node; node->left = build(node->left, from, mid); node->right = new Node; node->right = build(node->right, mid + 1, to); node->val = node->left->val + node->right->val; return node; } // the update function finds the nodes that cover the interval // and creates copies of them and their ancestors with the // updated values (they are O(log n) at most) Node* update(Node *node, int from, int to, long long val) { Node *uptNode = new Node; uptNode->from = node->from; uptNode->to = node->to; if(node->from >= from and node->to <= to) { uptNode->val = node->val + (node->to - node->from + 1) * val; uptNode->carry = node->carry + val; uptNode->left = node->left; uptNode->right = node->right; return uptNode; } uptNode->carry = node->carry; if(node->left->to >= from) { uptNode->left = update(node->left, from, to, val); } else { uptNode->left = node->left; } if(node->right->from <= to) { uptNode->right = update(node->right, from, to, val); } else { uptNode->right = node->right; } uptNode->val = uptNode->left->val + uptNode->right->val + (node->to - node->from + 1) * uptNode->carry; return uptNode; } /// a normal get sum function int getSum(Node *node, int from, int to) { if(node->from >= from and node->to <= to) return node->val; int ret = 0; if(node->left->to >= from) { ret += getSum(node->left, from, to); } if(node->right->from <= to) { ret += getSum(node->right, from, to); } int f = max(node->from, from); int t = min(node->to, to); return ret + (t - f + 1)*node->carry; } int main() { iostream::sync_with_stdio(false); cin.tie(nullptr); int n, q; cin >> n >> q; for(int i = 0; i < n; i++) cin >> nums[i]; root[0] = new Node; root[0] = build(root[0], 0, n - 1); int rootsCnt = 1; for(int i = 0; i < q; i++) { int type; cin >> type; if (type == 1) { int from, to, time; cin >> from >> to >> time; cout << getSum(root[time], from, to) << endl; } if (type == 2) { int from, to, time, v; cin >> from >> to >> time >> v; root[rootsCnt] = new Node; root[rootsCnt] = update(root[time], from, to, v); rootsCnt++; } } return 0; }