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?
 
    