config.yml and set future: false.]]>Summary of the question: The goal is to count the number of brilliant consecutive subarrays of a given array. What is a brilliant array? an array (that now is no more important if set or array) from which we can arrive at a set of consecutive numbers by taking the mean of two elements in the set (the procedure may obviously be repeated several times). The length of the given array does not exceed 4x1e5.
Initial thoughts:
Post-initial thoughts:
B
The question Solved; revision on the algorithm to add …
]]>[Disclaimer: All (or almost all) that is explained here is from the Steven and Felix Halim and Suhendry Effendy book.]
Articulation point in a graph: if you take out this node, your graph will split up in two parts ….. Bridge: the same thing would happen if you take such an edge out …..
The goal is to find such nodes or edges in an undirected graph. I have never really used this algorithm in any problem I have solved, as far as I remember :U … but it’s a fun one, like it has those moments where you go : Aaaaaaaaaaaa, that’s why :U (this thing: :U is such a mood)(I should just quit writing otherwise I will just continue jabbering and babbering about nonesense, so, let’s stop it here)
What would be the stupid way to find such vertices or edges? Just take out each node or edge one by one and check if the graph remains connected. The complexity would be O(Vx(V+E)), one is for taking out each node/edge, and the other for an algorithm to run through the graph, BFS or DFS, and check if we can access all nodes starting from one.
But let’s be wiser, and make some changes to DFS to make it serve our goal better; define two numbers to store for each node when applying DFS:
dfs_num : The iteration at which we visit a nodedfs_low : If R is the set of nodes in the DFS spanning subtree rooted at u, then dfs_low is the lowest dfs_num that can be found in R OR among the ones not in R but reachable by a back edge from R.
Let’s say we have done DFS over the graph and now we have all the numbers we wanted to store.
consider a vertex u connnected to v, and add the condition dfs_low(v) $\geq$ dfs_num(u). What does this mean?

This means that we have not been able to find a lower dfs_num in the DFS subtree rooted at v or among those connected to it by a back edge. In other words, the nodes visited during DFS after visiting the node v all have higher or equal dfs_nums than that of v, which also means that there is no back edge from nodes visited in DFS after v back to the nodes visited before that point, and hence u is an articulation point!
Exceptional Case: when the starting node of DFS has only one neighbor, it is obviously an articulation point; but, we cannot detectc it using the above process since it has the lowest dfs_num of all.
Detecting Bridges is similar, but the condition to check on vertices changes just a bit: dfs_low(v) $>$ dfs_num(u) . There is no equal as you can observe :U
Why?
]]>A Fenwick Tree (also Binary Indexed Tree (BIT)) is a useful data structure to calculate sum of a consecutive subset (also known as Range Sum Query (RSQ)) in an ordered set.
The advantage is that we can use it to update elements efficiently, in O(log n).
Another cool thing: we can use bit manipulation techniques for more efficiency.
Each node is responsible for the sum of elements in a coonsecutive subset; which one? the node $i$ keeps the sum for the subset $[(i - LSOne(i)+1), …, i]$. ($LSOne(i)$ for a binary number gives the least significant bit that is one. For example, for $6$ it would be $2$.)
Why is it structured like this? becuase then we can easily and efficiently:
First, if we want to compute $rsq(i,j)$, we can just calculate $rsq(1,j)$ and $rsq(1, i-1)$ and the substract them from eachother; so it boils down to computing $rsq(1,i)$.
if $i^{\prime} = i - LSOne(i)$ (what is does is simply removing the least significant one-bit and keeping the rest) did you what happened there? :D we had the node $i$ responsible for the subset $[(i - LSOne(i)+1), …, i]$, and then the node $i^{\prime}$ is responsible for $[(i^{\prime} - LSOne(i^{\prime})+1), …, (i - LSOne(i))]$, and … ; so, if we continue like that, till reaching zero, we get the sum of all elements from $1$ to $i$. \(rsq(1,i) = n_{i} + n_{i^{\prime}} + n_{i^{\prime \prime}} ...\)
The complexity? $O(log n)$.
Secondly, we want to update the element at the index $i$, Let’s say we want to add $v$ to it : what nodes would this update affect? all the nodes such as $j$ where $ i \in [(j - LSOne(j)+1), …, j]$; what are those? those that when you drop their least significant one-bit are less than $i$ but are larger than $i$: this part is slightly more tricky to digest, but the logic behind it is that we shouold start from $i$ and add something to it to push the least significant one-bit further. It is beacuse as long as this one-bit goes further, the remaining number would be larger than $i$ after removing it. To push this one-bit further, we can add the value of the least significant one-bit to it: $[(i + LSOne(i)), (i + LSOne(i) + LSOne(i + LSOne(i))), …]$
The complexity? again $O(log n)$.
The implementation is taken from the book Competitive Programmingn book 1, by Steven and Felix Halim and Suhendry Effendy.
#define LSOne(S) ((S) & (-S))
typedef vector<int> vi;
class FenwickTree {
private:
vi ft;
public:
FenwickTree(int n) {
ft.assign(n + 1, 0); // Fenwick Tree is 1-based index, so size n+1
}
// Function to update the Fenwick Tree with a new value at index idx
void update(int i, int value) {
while (idx <= n) {
ft[idx] += value;
i += LSOne(i); // Move to the next responsible node
}
}
// Function to compute the prefix sum from index 1 to idx
int query(int i) {
int sum = 0;
while (i > 0) {
sum += ft[i];
i -= LSOne(i); // Move to the parent node
}
return sum;
}
// Function to get the sum in the range [l, r]
int rsqe(int i, int j) {
return query(i) - query(i - 1);
}
};
Things to still add: Other operations that can be done on Fenwick Tree, their complexity, and the complete implementation.
]]>