I encountered a very strange bug while trying to implement persistent segment trees (the context isn't really relevant).
If is assign a variable like this:
nodes[id].lc = init(l,mid)
Sometimes nodes[id].lc
is -1, even though init()
never returns -1.
If however, I simply assign it like:
int id_l = init(l,mid);
nodes[id].lc = id_l;
The bug goes away. What is happening? Here is the code for greater context:
Here is the code that does not work:
#include <bits/stdc++.h>
using namespace std;
struct Node {
int lc,rc,val;
Node() : lc(-1), rc(-1),val(0) {
}
};
vector<Node> nodes;
int n,q;
vector<int> a;
///creates a new node for this interval and returns the id of it
int init(int l, int r) {
nodes.push_back(Node{});
int id = (int)nodes.size() - 1;
if ( l == r) {
nodes[id].val = a[l];
} else {
int mid = (l + r) / 2;
nodes[id].lc = init(l,mid);
nodes[id].rc = init(mid + 1, r);
cout << "nodes[id].lc = " << nodes[id].lc << "\n";
cout << "nodes[id].rc = " << nodes[id].rc << "\n";
nodes[id].val = nodes[nodes[id].lc].val + nodes[nodes[id].rc].val;
}
cout << "id = " << id << "\n";
return id;
}
int main() {
cin >> n >> q;
a.resize(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<int> root;
root.push_back(init(1 , n));
return 0;
}
The output for input 6 0 1 2 3 4 5 6
is
6 0 1 2 3 4 5 6
id = 3
id = 4
nodes[id].lc = 3
nodes[id].rc = -1
id = 2
id = 5
nodes[id].lc = -1
nodes[id].rc = 5
id = 1
id = 8
id = 9
nodes[id].lc = -1
nodes[id].rc = 9
id = 7
id = 10
nodes[id].lc = -1
nodes[id].rc = 10
id = 6
nodes[id].lc = -1
nodes[id].rc = -1
id = 0
The problem is that sometimes nodes[id].lc
is -1, even though id
is never -1 when it is returned from init
However, all we have to do to make the code work is change the init function to this:
int init(int l, int r) {
nodes.push_back(Node{});
int id = (int)nodes.size() - 1;
if ( l == r) {
nodes[id].val = a[l];
} else {
int mid = (l + r) / 2;
int id_l = init(l,mid);
int id_r = init(mid + 1, r);
nodes[id].lc = id_l;
nodes[id].rc = id_r;
cout << "nodes[id].lc = " << nodes[id].lc << "\n";
cout << "nodes[id].rc = " << nodes[id].rc << "\n";
nodes[id].val = nodes[nodes[id].lc].val + nodes[nodes[id].rc].val;
}
cout << "id = " << id << "\n";
return id;
}
All we did was introduce the variables id_l, and id_r, and now the output is:
(same input, 6 0 1 2 3 4 5 6
)
id = 3
id = 4
nodes[id].lc = 3
nodes[id].rc = 4
id = 2
id = 5
nodes[id].lc = 2
nodes[id].rc = 5
id = 1
id = 8
id = 9
nodes[id].lc = 8
nodes[id].rc = 9
id = 7
id = 10
nodes[id].lc = 7
nodes[id].rc = 10
id = 6
nodes[id].lc = 1
nodes[id].rc = 6
id = 0
So everything works fine, there are no more -1s.
What is happening here?