 what's up guys my name is Michael and welcome to my youtube channel today we are going to continue talking about finwick trees so this is going to be a longer in-depth explanation about finwick trees and i'm going to actually draw out the finwick tree with you guys but basically finwick trees are used for range query same thing as a segment but the reason why we use finwick trees is that segment trees are a little bit more complicated they take o of four n space complexity finwick trees are less complicated and they're more easily to implement range queries when i mean by range query i mean by when you have like an array and you want to sum up the values between indexes one to four or like two to five stuff like that so i kind of explain most of this back in the other video if you want to check it out it's in one of the cards down below with my previous video of finwick trees but let's talk about let's actually draw out a finwick tree itself but let's talk about the time complexities of finwick trees because i didn't do that in the last video so finwick trees it takes o of n space so if i have n elements right it would take o of n to create it it takes log of n to search in a finwick tree so that's good it takes log of n to update an element in a finwick tree which is also good it takes n log n time to create a finwick tree here i have an array index from zero and i have three two negative one six five four negative three three seven two three and here what i did was i basically drew the tree here so i have 11 nodes in this tree which is one more than the corresponding values of the array that we're given so in our tree zero is a dummy node that doesn't really store anything any information of our whole array the rest of the nodes nodes one to 11 does store information it stores the prefix sum of different ranges so that's what it does let's talk about why the these nodes one two four eight ten are the children of zero so why zero the parent of two four eight and ten so let's look at this look at the binary representation of two base ten is going to equal one zero so two to zero two to one yeah as a base two and if i were to flip the rightmost bit so the rightmost set bit is this this one this value of one right this is this this value is the one that's set if i flip it now it becomes zero i get zero zero which represents two zero right so that's right that's our parents there look at four is binary representation so four is binary representation is one zero zero right this rightmost set bit is one and if i were to flip it and it becomes zero it becomes zero zero zero and that's equal to zero all right so that's why zero is the parent of four zero is the parent of two so that's why you drew zero as the parent of two and four and we could go on with eight and ten let's do like an eight eighth binary representation is zero zero right two which then it equals to if i flip this rightmost bit flip this this is going to become zero zero zero zero which is equal to zero so that's why zero is the parent of eight and let's look at ten zero one zero if i were to flip the rightmost set bit here i would get uh if i flip this rightmost set bit here this one to go back to zero right i'll get uh one zero zero zero base two and this is equal to eight in base ten that's why eight is a parent of ten so as you can see here this eight is the parent of ten like ten is a child of eight so that's why that's the case of here let's look at eleven binary representation eleven is one zero one one right base two and if i flip the rightmost set bit flip this this is going to get me one zero uh one zero which is ten and that's why eleven is a child of ten and if you keep going so on and so forth you're going to get all of the in draw it out you're going to get all these values okay so basically to get the parents of whatever index i'm at so whatever node for whatever node is i want to get the parent what do i do i basically just write out the binary representation of the index then i flip the rightmost set bit and that will be the parent so if i want to get the parent of ten what do i do write ten in its binary representation find the rightmost set bit flip it that gets me eight eight is the parent of ten so you could do that for the rest of these nodes okay so now that we understand where we got the parents of each individual children and their corresponding indexes let's let's fill this tree up with the prefix some information okay so guys before we get started about generating the prefix some let's note that any number can be represented as a power of two so if i have ten here i could represent ten as a power of two two to the third plus two to the first right eight plus two eight plus two is equal to ten well about eleven i could represent eleven as a power of two how do i represent eleven as power you could have it as two to the third plus two eight plus two plus one two to the zero right eight plus two plus one that's a power of ten okay you could have five as a power of two two to the second plus two to the zero okay why is that because five is equal to four plus one which is five okay so that's why any number can be represented as a power of two so basically the finwick tree uses the idea of having the powers of two as a parent to compute its next prefix some right so the parent of ten eight it uses this value to compute its prefix some of the next value let's start doing this now the first value of the node zero is a dummy node so it stores zero okay so that's why its prefix some is zero all right let's start at one now one represents one is equal to zero plus two to this is zero which is one right zero plus one is one reason why i'm saying zero is because zero is the parent of one i'm representing this as a parent okay so what am i saying here starting from parent zero the sum of the next one element two to zero is going to be stored at index one so what does that mean my prefix sum of zero the parent of zero is zero sum of next one element from index zero is three zero plus three so that's why one is going to at index one at array index one i'm going to store zero plus three because from this element of zero the next one element is going to be itself so i'm going to store three so i'm also going to indicate that the range from zero to zero is going to be stored at index one so i'm going to put zero to zero the range of zero to zero is going to be stored at index one from zero to zero i'm going to store at index one all right guys so now two what can two be represented in terms of the parent of zero it's zero plus two to the one okay so now from the sum the first two elements from the starting point of our parent of zero i'm going to sum that and store it in the index of two so what is the sum from two values from our first value of index zero three plus two right because that's the first two values at that i'm summing from the start of our parent of zero so that's going to give us five now what is the range that i'm summing from zero to one that's what i'm summing from so i'm going to put that here that's the range that i'm summing from now let's look at three three is equal to what is three equal to including the parent well three's parent is two so that's two to the one plus two to the zero okay okay so from this representation two and one starting from index two what is the next sum of the next one element all right two to the zero is one so what is the next sum of the next one element well starting from index two the sum of the next one one element is just going to be negative one okay because i'm starting from two and the next sum of the next for one element is just going to be negative one so i'm going to put negative one here so what is the range that i'm summing from okay what is the range i'm summing from starting from index two well to get to negative one it's going to be the range of two to two because i'm starting from two and i'm ending at two So that's why I'm going to put 2 to 2 here. Alright, let's look at 4. What is 4's parent? 4's parent is 0. So I put 0 plus, uh, how do I represent 4 in terms of 0 of its parent? That's 2 to the second, okay? So now, starting from index 0, what is the sum of the first 4 elements? That's what I'm going to store at index 4, okay? So now the sum of the first elements starting from 0, starting from 0, the first sum of first 4 elements, 1, 2, 3, 4, from here to here, okay? That's the sum of the first 4 elements. That's going to be equal to 3 plus 2 plus negative 1 plus 6, 10. So I'm going to put 10 at 4. The range that I'm summing from first 4 elements starting from 0 is going to be between 0 to the index 3. That's what I'm going to put here. So what is 5 equal? 5 is equal to what is the parent? The parent is 4. Terms of representation of 2, that's going to be 2 to the second plus 2 to the 0, okay? Because 5 is equal to 4 plus 1, okay? So now, starting from index 4 at index 4, what is the first 1 sum starting from index 4? So from here, the first sum, okay? From index 4, that's just going to be 5. So I'm just going to store 5 at index 5. So I'm going to put 5. And what is the, in terms of the range I'm summing from? That's just going to be 4 to 4, okay? Because at index 4, the range I'm summing is just going to be itself. So index 4 is going to be 4 to 4. Let's look at 6. What is 6 parent? 6 parent is 4. We represent that as 2 to the second. 2 to the second plus 2 to the first, okay? Because it's 4 plus 2 is equal to 6. So starting at index 4, right? What is the sum of the next 2 elements, right? The sum of the next 2 elements. The reason why I'm looking at the next 2 elements is because that's what this is equal to, right? Next 2 elements starting at index 4. What is that? So starting at index 4, that's going to be 5 plus 4 and that's going to give us 9, okay? So I'm going to put 9 here. And what is the range between that? The range is going to be between 4 to 5. Let's look at 7. What is 7? 7 is equal to, its parent is 6. So that's 2 to the second plus 2 to the first, which is 6. Then we need to add 1, so 2 to the 0, okay? So what is the next 1 element from starting from index 6? Okay, so starting from index 6. What's the sum of the next 1 element? So starting from index 6. Our index 6 is negative 3, okay? So index 6 is negative 3. So the next sum of the next 1 element is just going to be negative 3, okay? So that's going to be negative 3. And the range is just going to be 6 to 6, okay? So let's look at 8. Starting from 8, 8 represents the parent of 8 is 0. So we put 0 here, okay? So let's represent 8 in terms of its parent is 0. 0 plus 2 to the third, that will give us 8, okay? So the sum of the values of the next 8 elements, 2 to the third, what is that going to be? That's going to be 3 plus 2 plus negative 1 plus 6 plus 5 plus 4 plus negative 3 plus 3. So basically we're summing up from next 8 elements starting from 0 is going to be here, up to here, okay? So that's going to be the sum from 0 to 7. And then if you put all these values in a calculator, which I'm going to do right now, that's going to give us 19. So let's look at 9. 9 is equal to 8 plus, let's just put 8 plus 2 to the 0, which is 1, okay? I don't feel like writing the binary equivalent of 8. But yeah, because 8 is, we got 8 from the parent, okay? So now starting from index 8, what is the next sum of the next 1 element, okay? So from index 8, the sum of the next 1 element is just going to be 7, okay? So that's going to put 7 here. And that's going to be the sum between 8 to 8. So we got 10. 10 is equal to 8 plus 2 to the 1st, okay? Because 10 is equal to 8, 8 is the parent of 10. So yeah. So now what is the sum starting from index 8? The next sum of next 2 elements, okay? So the next 2 elements is going to be, the sum from starting index 8 is going to be 7 plus 2, which is going to give us 9. So for 10, we're going to put 9, okay? So now the next 2 elements for 8 is going to be 9. And that's going to be the range of 8 to 9, the sum between the range of 8 to 9. All right, now let's look at 11. 11 is equal to 10 plus 1, which is 2 to the 0, okay? So now the sum of the next 1 element, what is that? Starting from index 10, starting from index 10, the next 1 element is just going to be 3, right? Because there's nothing after, we're at 10 right now. The next 1 element is just going to be 3, okay? At index 10. So that's just, we're just going to put 3 here. And that's just going to be the sum between 10 to 10, okay? All right, so that's basically summing up all the values here. Okay, so this is not the most efficient way of creating the tree, but it was a good way to explain to you guys and show you guys and draw it out of what I did to create the tree, okay? So let's say I want to start searching from ranges between 0 to 5, okay? So where do I start searching first? I should actually start searching at index 6 because 6, as you could see from our node of 6, it is the last time we restore an index of 4 to 5, right? So if I want to start summing for 6, I just take the value at index 6, which is 9, and this 9 is for the ranges from 4 to 5. So now what I'm going to do is I'm going to get the parent of 6 and the parent of 6 is going to be 4. So I'm going to add whatever value is at index 4, so I add by 10. So now that I add at by index 4, I'm going to get the parent of 4 now and that's going to be 0 and the value at 0 is going to be 0, so plus 0. So that's going to give me values of 19. And if you want to look at the ranges, for 9 is 4 to 5, for 10 is 0 to 3. So you're going to have this one 0 to 0. So then you're going to have 0 to 5. This range is going to be 0 to 5, okay? So if I draw it out, you could be, look at this 4 to 5. 4 to 5, sum these up, right? And then if you sum from the parent of 4, which is going to be 0 to 3. So you sum up 0 to 3 and then 0 to 0. So then if you look at this, this whole sum is just going to be 0 to 5. If you look at the whole sum, it will actually sum up to 0 to 5. So yeah, and to get each individual parent, all you have to do is just flip the rightmost bit that's set for like the bit of 6. I'll just flip the rightmost bit and that'll give me the parent of 4 and then for 4, rightmost bit, I'll flip it and I'll get the parent, which is at index 0. So yeah, that's how you would get the searching for the sum from 0 to 5. So let's say I want to start summing up. I want to find the sum between ranges 0 to 9. So the index value of 0 to 9. So what do I start looking for? I first start looking at index 10 because at index 10, this is index 10, right? It has the ranges of 8 to 9. So that's going to help me find the sum of all the other values from 0 to 9. So what do I do first? I look at the value at index 10. So the value at index 10 at index 10 in our tree is 9. So I'm going to first write the value of 9, the value at index 10 down 9. Then I need to find the parent of the value at index 10. Okay? The value at index 10. So what is the parent of 10? The parent of 10 is 8. So I'm going to sum up the parent of 10 and sum of that value of index 8. So that's going to be 9 plus 19. So now once I've finished the value at index 8, I'm going to sum the parent of 8, which is going to be 0. And the value at index 0 is going to be 0. So 19 plus 9 plus 0 is going to be 28. And if you were to draw this out, the range is 9 at index 10, right? This range is 8 to 9, right? At index 10, the range is 8 to 9. From the parent of the value at 9 of index 10 is going to be 8. And let's look at the value of 8. The ranges of 8 is 0 to 7. So we're going to do write 0 to 7 here. And then if you were to draw it out, this was 0 is 0 to 0. So basically, if you want to draw out this actual sum, 8 to 9 would be this here to here, right? And then 19 would be the sum from 0 to 7. So that's here, here to... And if you were to sum these two up, that will get you to 0 to 9, right? If you add these two values up, this value and this value will get you 0 to 9, okay? Let's say I want to find the range sum between 0 to 6. Well, what is the 0 to 6? The next value, the next value is 7. So I'm going to start at index 7, okay? So index 7 is the sum of... At index 7, I have negative 3. And negative 3 is the range between 6 to 6. So now I have to go to the parent. What is the parent? The parent of 7 is 6. So now I'm going to add the value of 6, whatever value I add at index 6, which is 9. So I'm going to plus 9. And this is the range between 4 to 5, okay? And now I need to keep going up to the parent, add to the parent also. So what is the parent of ranges of index 6? That's going to be 4. At index 4, the value at index 4 is 10. So I'm going to add by 10. And add by 10, then the range at index 4 is 0 to 3. So I'm going to put 0 to 3. And then now I'm at the parent, which is the root is 0, okay? 0 to 0. So now if you were to sum these up, you would get 16, okay? So now if you were to draw this out, 0 to 3 is this sum, 0 to 3, okay? And then now 4 to 5 is this sum, which is the 9, the 4 to 5, okay? And then 6 to 6 is just 6. So now if you look at this by itself, if you sum all these individual segments up, you get 0 to 6, right? If you add all this value, this segment, this segment, and this segment, you get a range from 0 to 6. So what is the worst case scenario of going through this tree? The worst case scenario of searching is going to be the height of the tree. And that's going to be at worst case log base 2 of n. So let's go back to the idea of how to get a parent of a certain node, okay? At a certain index. Let's say I want to get the parent of 11. So 11 in binary is 1011, okay? So remember, to get the parent, the parent of the current node you're at, the current index, you have to set the right most significant bit back to 0. So that's 1011. I have to set it to 0. That's 1010 and that gives us 10. But how do I do that? One way to do it is actually just to get the 2's complement and with the original and then subtract from the original. So if I want to get the 2's complement of 1011, what do I do? I just flip all the bits. So I get 0, 1, 0, 0. I add it by 1. So then I get 0, 1, 0, 1. Then I have to end it with the original. The original is 1011. The original of 11 is 1011. End it with 0, 1, 0, 1. And this gives us 1. True, true is true. True false is false, 0. True false is false, true false is false. That gives us 0, 0, 0, 1. And then now I have to subtract 0, 0, 1 from 1, 0, 1, 1. 1, 0, 1, 1 minus 0, 0, 0, 1. And that gets rid of this last bit. This last bit now gets set to 0. So that gives us 1, 0, 1, 0. Which base 2 is it going to equal to 10? Okay? From base 2 to decimally, it gives us 10, which is actually the parent of 11. So this is how you do it programmatically. In the program, you just flip all the bits using the not symbol. And then you end it with the original, then subtract from the original. So if you wanted to do it programmatically, that's how you would do it. Okay? Because there's no real possible way to do it to set the right, to get the right and the most bit and set it to 0. So that's what you have to do. So the time complexity of getting the parent of a single node in our FinWikTree is going to be 0 of 1. Because it will only take 0 of 1 time. Constant time to get a certain value, to get a parent of a certain value in our tree. Okay? All right, guys. So now let's figure out how to do this efficiently using the parent instead of recalculating over and over again to generate our FinWikTree. Okay? All right, guys. So what I did was I basically just redrew the whole tree and put all the values with zeros. Okay? So the same thing, put all the values with zeros. So a more efficient way to do this is actually to use this function called getNext, which is you're going to get, whenever you update an element in your FinWikTree, you are going to propagate the changes to the next node that's going to get affected by your previous change. So that's what this getNext does. So to get the next node that is propagated from your change, you would use something called getNext, which is what you do is take the two's complement, you end it with the original, and then you add it to the original. Okay? So that gets you the next node that would get affected by the change that you just made. Okay? So let's go back to the original value. Let's start from zero. Okay? So zero, the first element that we're going to sum up from zero is three. Right? So we're going to add three to our first value. So let's change this value. So three, okay, but this is just not enough. Right? We have to propagate the changes to the other nodes that would get affected by changing this value to three. So let's get the next value of our index of one and propagate those changes to the next value. So our index of one is, if you write it in binary, it's going to be zero, zero, zero, zero, one. I don't know if zero is a tag on. Okay? Let's get the two's complement. So that's what you do is you flip all the bits, one, one, one, zero, and then you add one. So then plus one is going to be one, one, one, one. So now we're going to end it with the original. So when you end it with the original, you get zero, zero, zero, zero, and then one. Okay? Now we're going to add one to the original. This is the value we have to add it to the original. So we're going to add this to our value one. So zero, zero, zero, zero, one plus zero, zero, zero, zero, one. This is going to give us zero, zero, zero, one, zero, two to the one, which is going to equal two, two. So our next value we're updating is two. So now we're going to change at index two to become three. So that changed that value. And then we have to propagate the next value of two now. So let's do that. So if you continue doing this function of adding, getting the two's complement and ending it with the original, adding it to the original. If you do the next value for two, you'll get four. And then four, you'll get eight. So then let's propagate those changes to a four and eight. So let's just do that. So here, let's make this. So yeah. So at eight, if we get the next element of eight, we actually end up getting greater than 11. So we end there. Okay. So the next of eight, we end there. So we're not going to keep going. Propagating. So the amount of time it took to update all the values of three is going to be O of log of N. If you just count the number of times it took. All right. So now let's look at the next index that we're going to update, which is one. So at one, we'll look at index two. And then now we're going to add the values of two to whatever was currently at two. So that's going to do three plus two is going to be five. So now I'm going to set this to five. And then I'm also going to propagate the changes using the next function, which is going to be four and eight. So this is going to be five. Okay. And then when you hit eight, eight's next is greater than 11 the size of our finwick tree. So then we stop. All right, guys. So now let's look at index two index two is negative one. So what we're going to do is we're actually going to go to index three and set the value to be negative one because three is a range of two to two. So that's why we're going to set three is going to equal to index three. We're going to set to negative one and then we're going to find the next value of index three. So if you were to actually calculate yourself and you would actually get four. So three's next is actually four. If you follow this formula, I don't feel like drawing it out again, but three's next is basically four. So then now what we're going to do is we're going to add negative one to whatever value was at four and update those changes. So that's going to be negative one plus five, which is going to be four. So we're going to change this to be four. And then now we have to propagate the changes. Four is next is eight. So then now we have to also add negative one to the value of eight. So this also becomes four. So now we're going to go to the next index that we're updating. So last time we did two and we're going to go to three now. So now at three, what we're going to do is we're going to go to the next index, which is four. So now at index four, we're going to add six to it. So we're going to change this to become four plus six is going to be 10. So this is going to be 10. Okay. And then now we have to propagate the changes to the next element of four, which is eight. The next element of four is eight. So now we're going to prop add six to eight also. So this is also going to become 10. So now we're going to go to four now and we're going to add the value. So the range of four is four to four. So that's at index five. So we are going to just put five at index five. So yeah, because the sum of four to four is just itself. So we're going to put at index five or just put five because that's the value of our array. So now if you were to apply the same formula to five, fives next is actually six. So we're going to change six to become five also. So then six next using this formula is eight. So now we have to propagate our changes of six into eight. So then now we're going to add five to whatever value at eight. So it's going to be five plus 10, which is going to be 15. So now we're going to add whatever value at go to the next index. We're going to go to add value at five, right? So now we're going to go to whatever range that effects. So that's that'll be six, right? So five, we're going to go to six and we're going to add whatever value at our index five into six at index six. All right. So then four plus five here is going to be nine. So we're going to change six to nine. All right. So six is next is eight and so we have to propagate our change from the next of six. So that will be four plus 15. So that'll be 19. So now we're going to change eight to become nine. Now we're going to update at index six. If we look down here, uh, index six is five to six. My bad. This is supposed to be six to six. So yeah, six to six, it'll be minus three because it's the value of six seven's next is also eight. So now we have to add negative three proper propagate to change the negative three into our next value of eight. So we have to do 19 minus three, which is going to change to 16. So now we're going to update seven. Uh, so we're going to go to index eight and then because there's a value index eight, we'll just add three or current value at seven three to whatever value eight. So 16 plus three is going to be 19. Now we're going to add the update the value of eight of the index eight. So we're going to check the index of nine. So index nine is just the sum of eight to eight. So that'll just be seven. Okay. So this is going to become seven because that's our value eight. All right. So nine's next node is 10. So 10 is going to also become seven. So let's change that. All right. So 10's next is outside the range. So we don't update that. So now let's go to we're going to update nine. So how do we update nine? We're going to go to the 10th index. So at the 10th index, there's a value here. So we're going to up we're going to add two to the value of at this location. So this is going to be two plus not a seven. It's going to be nine. Now we are at the final element of our array of index 10. So we're going to go to 11. And 11 is just 10 to 10. So we're just going to add three and then 11's next is outside the bounds. So we don't continue after that. So yeah, that's pretty much it. All right, guys. So now that we're done because to update each element of the in the Finwick tree is log of n time, right? A log it takes log of n based on the tree going down to the tree. And then because we have n elements in our array, it'll be n times log of n to construct our Finwick tree. All right. So let's think about what would happen if I want to update a value. So let's say I won't add next three and then I want to update it to nine. So so what am I going to do? Well, the difference between nine and six is three. So that's a plus three difference, right? So that means that for all the values, I'm going to have to change it by a difference of three. Okay. So now at I'm going to go to index four in our tree, which is this four and I'm going to add three to it. Okay. So I'm going to add three to it. This is going to become 13. Now I have to update the next value of four. So that'll be four is next is eight. So now I need to change eight by adding three eight. So that'll be 19 plus three is going to be 22. So now it's next is outside the range. So it's done and the amount of time to update an element would just be of log n because that's the height of the tree to update an element. So yeah, let's go over another example. Let's say for we're going to update four. So to do that, let's say we are going to change five through six. So five is going to become six and that's going to be a difference of plus one. So now we're going to go up to index five, right? And we're going to add one to it. So it's going to be five is now going to become six five plus one is now going to be up six. And then now we have to update the next of five. So that will be who fives next fives next is six. So now I have to add one to fives next up six. So nine plus one is going to be 10. So let's change this to 10 then six next is eight. So we have to add one to whatever value at eight. So then now we're going to change 22 to become 23. So yeah, so the amount of time it would take to update this whole thing like tree would be of log n because you're just going to the next element and change it. So yeah, that's all we have to talk about. Finder trees rate comp subscribe. I hope this is a good in-depth tutorial. Check you guys later. Peace.