#include <iostream>
using namespace std;
typedef long long ll;
void updateSegementLazyTree(ll *tree , ll *lazy , ll low, ll high,ll startR ,ll endR ,ll updateValue ,ll treeNode)
{
//before using current node we need to check weather currentnode has any painding updation or not
if (lazy[treeNode]!=0)
{
//update painding updation
tree[treeNode] += (high-low+1)*lazy[treeNode];
//transfer update record to child of current node if child possible
if (low!=high)
{
//that's means child possible
lazy[treeNode*2] += lazy[treeNode]; //append update to left child
lazy[treeNode*2+1] += lazy[treeNode]; //append update to right child
}
lazy[treeNode]=0;//remove lazyness of current node
}
//if our current interval [low,high] is completely outside of the given Interval[startR,endR]
if (startR >high || endR <low || low>high)
{
//then we have to ignore those path of tree
return;
}
//if our current interval is completely inside of given interval
if (low >=startR && high <=endR)
{
//first need to update the current node with their painding updation
tree[treeNode] += (high-low+1)*updateValue;
if (low!=high)
{
//that's means we are at the non-leaf node
lazy[treeNode*2] +=updateValue; //so append lazyness to their left child
lazy[treeNode*2+1] +=updateValue;//append lazyness to their right child
}
return;
}
//partially inside and outside then we have to traverse all sub tree i.e. right subtree and left subtree also
ll mid=(low+high)/2;
updateSegementLazyTree(tree , lazy , low, mid, startR , endR , updateValue , treeNode*2);
updateSegementLazyTree(tree , lazy , mid+1, high, startR , endR , updateValue , treeNode*2+1);
//while poping the function from stack ,we are going to save what i have done....Ok!!!!
//update tree node:-
tree[treeNode] = tree[treeNode*2] + tree[treeNode*2+1]; //left sum+rightsum(after updation)
}
ll getAnswer(ll *tree ,ll * lazy , ll low, ll high ,ll startR,ll endR , ll treeNode)
{
//base case
if (low>high)
{
return 0;
}
//completely outside
if (low >endR || high <startR)
{
return 0;
}
//before using current node we need to check weather currentnode has any painding updation or not
if (lazy[treeNode]!=0)
{
//i.e. if we would have added x value from low to high then total changes for root node will be (high-low+1)*x
tree[treeNode] += (high-low+1)*lazy[treeNode];
if (low!=high)
{
//if we are at non-leaf node
lazy[treeNode*2] += lazy[treeNode]; //append updateion process to left tree
lazy[treeNode*2+1] += lazy[treeNode];//append updation process to right tree
}
lazy[treeNode]=0;
}
//if our current interval is completely inside of given interval
if (low >=startR && high <=endR)
{
return tree[treeNode];
}
//if our current interval is cpartially inside and partially out side of given interval then we need to travers both side left and right too
ll mid=(low+high)/2;
if(startR>mid)
{
//that's means our start is away from mid so we need to treverse in right subtree
return getAnswer( tree , lazy , mid+1, high, startR, endR , treeNode*2+1);
}else if(endR <= mid){
//that's means our end is so far to mid or equal so need to travers in left subtree
return getAnswer( tree , lazy , low, mid, startR, endR , treeNode*2);
}
ll left=getAnswer( tree , lazy , low, mid, startR, endR , treeNode*2); //traverse right
ll right=getAnswer( tree , lazy , mid+1, high, startR, endR , treeNode*2+1); //and left
return (left+right);//for any node total sum=(leftTreeSum+rightTreeSum)
}
int main()
{
int nTestCase;
cin>>nTestCase;
while(nTestCase--)
{
ll n,nQuery;
cin>>n>>nQuery;
ll *tree=new ll[3*n]();
ll *lazy=new ll[3*n]();
while(nQuery--)
{
int choice;
cin>>choice;
if (choice==0)
{
ll startR,endR,updateValue;
cin>>startR>>endR>>updateValue;
//0:- start index , n-1 end index ,1 treeIndex tree is our segment tree and lazy is our lazy segment tree
updateSegementLazyTree(tree , lazy , 0, n-1, startR-1 , endR-1 , updateValue , 1);
// for (int i = 0; i < 3*n; ++i)
// {
// cout<<i<<"\t"<<tree[i]<<"\t"<<lazy[i]<<endl;
// }
}else{
ll startR,endR;
cin>>startR>>endR;
ll answer=getAnswer(tree , lazy , 0, n-1 , startR-1 , endR-1 , 1);
cout<<answer<<endl;
}
}
}
}
updateSegementLazyTree()
take two arrays of size 4*n
because the total number of possible nodes with the length of log(n)
will be 2*2^log(n)
that at most is 4*n
. Then we also need interval[startR,endr]
and updateValue
that we maintain through recrusion. Tree[treeNode]
represents the sum of all elements from left and right.
Sample input looks like:
1
8 6
0 2 4 26
0 4 8 80
0 4 5 20
1 8 8
0 5 7 14
1 4 8
So for the first query we have to update 2-4
with +26. Instead of updating all elements between 2-4 we just store it in our lazy tree and whenever we access any node from the tree we first check weather this node has any pending update. If there are no pending updates, then complete and shift this to their child.
q1:- 0 2 4 26
tree[0,78,78,0,26,52,0,0,0,26]
try to make tree index; for left tree(2*i+1)
and right(2*i+1)
1-st index is at least 78 i.e. top of tree so from [0,n-1]
current max is 78.
tree[treeNode] += (high-low+1)*lazy[treeNode];
If we add x
from low index to high then in overall sub array i
have added (high-low+1)*x ; -1
because of indexing from 0
.
Then, before accessing any node from tree we lazy check weather that node has any pending update. if (lazy[treeNode]!=0)
If it has, then update and transfer lazy to their child. Keep doing that for left subtree and right subtree as well.
Then we reach getAnswer()
within range[startR,endR]
As I mentioned before, we first check for pending updates for each affected node. If true then it completes that update and call recursively left and right subtree according to the interval.
At the end we have the sum of leftSubtree
and sum of rightsubtree
of root node, add them and return them.
Time Complexity
In update, getAnswer()
, in worst case will have to traverse the entire tree i.e. height of tree O(2*Log N)
. 2*log n
because it is the worst case we have to travel in left and right subtree e.g. for interval [0-n-1]
.
For k
query, overall time complexity would be O(K*log n)
.