In this HackerEarth Repair this tree problem solution You are given a rooted tree T of n nodes and a graph G of n nodes. Initially, graph G has no edges. There are two types of queries:
  1. 1 x y w: Add an edge of weight w between nodes x and y in G
  2. 2 v p: Consider that the edge between v and its parent in T is deleted which decomposes T into 2 connected components. You need to find the sum of weights of all edges like x in G such that:
  3. The weight of x is divisible by p
  4. If an edge is added in T between the same endpoints as x then again we will get a tree (it will connect the two components). Note that the edge is deleted only for that particular query. 

HackerEarth Repair this tree problem solution


HackerEarth Repair this tree problem solution.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 14, lg = 18, maxv = 1e6 + 14;
int n, q, par[lg][maxn], h[maxn], st[maxn], en[maxn];
vector<int> prs[maxv], g[maxn];
struct Node{
    Node *L, *R;
    ll iman;
    Node() : iman(0), L(0), R(0){}
    void arpa(){
        if(L)  return ;
        L = new Node();
        R = new Node();
    }
    void add(int p, int x, int l = 0, int r = n){
        if(l + 1 == r){
            iman += x;
            return ;
        }
        arpa();
        int mid = l + r >> 1;
        if(p < mid)
            L -> add(p, x, l, mid);
        else
            R -> add(p, x, mid, r);
        iman = L -> iman + R -> iman;
    }
    ll get(int s, int e, int l = 0, int r = n){
        if(s <= l && r <= e)
            return iman;
        if(e <= l || r <= s)  return 0;
        int mid = l + r >> 1;
        return (L ? L -> get(s, e, l, mid) : 0) + (R ? R -> get(s, e, mid, r) : 0);
    }
}  seg[maxv];
void init(){
    bool isp[maxv];
    memset(isp, 1, sizeof isp);
    for(int i = 2; i < maxv; i++)
        if(isp[i])
            for(int j = i; j < maxv; j += i)
                isp[j] = 0, prs[j].push_back(i);
}
void dfs(int v = 0){
    static int t = 0;
    st[v] = t++;
    for(auto u : g[v])
        dfs(u);
    en[v] = t;
}
int lca(int v, int u){
    if(h[v] > h[u])
        swap(v, u);
    for(int i = 0; i < lg; i++)
        if(h[u] - h[v] >> i & 1)
            u = par[i][u];
    for(int i = lg - 1; i >= 0; i--)
        if(par[i][v] != par[i][u])
            v = par[i][v], u = par[i][u];
    return v == u ? v : par[0][v];
}
int main(){
    ios::sync_with_stdio(0), cin.tie(0);
    init();
    cin >> n >> q;
    for(int i = 1; i < n; i++){
        cin >> par[0][i];
        par[0][i]--;
        h[i] = 1 + h[ par[0][i] ];
        g[ par[0][i] ].push_back(i);
    }
    dfs();
    for(int k = 1; k < lg; k++)
        for(int i = 0; i < n; i++)
            par[k][i] = par[k - 1][ par[k - 1][i] ];
    int lastAns = 0;
    while(q--){
        int t, v, u, w;
        cin >> t;
        if(t == 1){
            cin >> v >> u >> w;
            v--;
            u--;
            v = (v + lastAns) % n;
            u = (u + lastAns) % n;
            for(auto p : prs[w]){
                seg[p].add(st[v], +w);
                seg[p].add(st[u], +w);
                seg[p].add(st[lca(v, u)], -2 * w);
            }
        }
        else{
            cin >> v >> w;
            v--;
            v = 1 + (v + lastAns) % (n - 1);
            cout << (lastAns = seg[w].get(st[v], en[v])) << '\n';
        }
    }
}

Second solution

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int maxn = 2e5 + 100;
const int maxp = 1e6 + 100;
void debug();
vector<int> get_primes(int x);

struct Segment{
    int root;
    vector<int> left, right, val;

    Segment(){
    root = 0;
    left.push_back(0);
    right.push_back(0);
    val.push_back(0);
    }
    
    int get(int l, int r, int st, int en, int id){
    if(l <= st && en <= r)
        return val[id];
    if(r <= st || en <= l)
        return 0;
    int mid = (st + en) >> 1;   
    return get(l, r, st, mid, left[id]) +
        get(l, r, mid, en, right[id]);
    }

    int add(int ind, int x, int st, int en, int id){
    val.push_back(val[id]);
    left.push_back(left[id]);
    right.push_back(right[id]);
    id = left.size() - 1;
    val[id] += x;
    
    if(en - st < 2)
        return id;
    int mid = (st + en) >> 1;
    if(ind < mid) {
        int hlp = add(ind, x, st, mid, left[id]);
        left[id] = hlp;
    }
    else {
        int hlp = add(ind, x, mid, en, right[id]);
        right[id] = hlp;
    }
    return id;
    }
    
    void add(int ind, int x){
    root = add(ind, x, 0, maxn, root);
    }
    
    int get(int l, int r){
    return get(l, r, 0, maxn, root);
    }

    void print(){
    cerr << "root = " << root << endl;
    for(int i = 0; i < left.size(); i++){
        cerr << i << ": " << left[i] << ' ' << right[i] << ' ' << val[i] << endl;
    }
    cerr << endl;
    for(int i = 0; i < 10; i++)
        cerr << get(i, i + 1) << ' ';
    cerr << endl;
    }
}segment[maxp];
int n;

namespace tree{
    const int maxL = 20;
    vector<int> vc[maxn];
    int st[maxn], en[maxn], last_index;
    int par[maxL][maxn];
    int h[maxn];
    
    int get_par(int v, int p){
    for(int i = 0; i < maxL; i++)
        if((p >> i) & 1)
        v = par[i][v];
    return v;
    }

    int LCA(int u, int v){
    if(h[u] < h[v])
        swap(u, v);
    //h[u] >= h[v]
    u = get_par(u, h[u] - h[v]);
    if(u == v)
        return v;
    for(int i = maxL - 1; i >= 0; i--)
        if(par[i][u] != par[i][v]){
        u = par[i][u];
        v = par[i][v];
        }
    return par[0][v];
    }
    
    void dfs(int v){
    st[v] = last_index++;
    for(int u: vc[v]){
        h[u] = h[v] + 1;
        dfs(u);
    }
    en[v] = last_index;
    }

    void initialize(){
    dfs(0);
    for(int i = 1; i < maxL; i++){
        for(int v = 0; v < n; v++)
        par[i][v] = par[i - 1][par[i - 1][v]];
    }
    }
    
}
void pre_process();

int32_t main(){
    pre_process();
    //debug();
    int q;
    cin >> n >> q;
    for(int i = 1; i < n; i++){
    int p;
    cin >> p;
    p--;
    tree::par[0][i] = p;
    tree::vc[p].push_back(i);
    }
    
    tree::initialize();
    int lastAns = 0;
    while(q--) {
    int type;
    cin >> type;
    if(type == 1){
        int x, y, w;
        cin >> x >> y >> w;
        x--, y--;
        x = (x + lastAns) % n;
        y = (y + lastAns) % n;
        int par = tree::LCA(x, y);
        //cerr << "       par : " << par << endl;
        vector<int> primes = get_primes(w);
        for(int p: primes){
        Segment &seg = segment[p];
        
        //cerr << "    add " << p << ' ' << tree::st[par] << ' ' << tree::st[x] << ' ' << tree::st[y] << endl;
        seg.add(tree::st[par], -2*w);
        seg.add(tree::st[x], +w);
        seg.add(tree::st[y], +w);
        }
    } else if(type == 2){
        int v, p;
        cin >> v >> p;
        v--;
        v = 1 + (v + lastAns) % (n - 1);
        //cerr << "    get " << p << ' ' << tree::st[v] << ' ' << tree::en[v] << endl;
        cout << (lastAns = segment[p].get(tree::st[v], tree::en[v])) << '\n';
    }
    }    
}

vector<int> primes[maxp];

void pre_process(){
    for(int i = 2; i < maxp; i++)
    if(primes[i].empty())
        for(int j = i; j < maxp; j += i)
        primes[j].push_back(i);
}


vector<int> get_primes(int x){
    return primes[x];
}


void debug(){
    int n;
    cin >> n;
    Segment seg;
    while(true){
    int type;
    cin >> type;
    if(type == 1){
        int ind, x;
        cin >> ind >> x;
        ind--;
        seg.add(ind, x);
    } else if(type == 2){
        int l, r;
        cin >> l >> r;
        l--;
        cout << seg.get(l, r) << endl;;
    } else if(type == 3){
        seg.print();
    } else {
        for(int i = 0; i < n; i++)
        cout << seg.get(i, i + 1) << ' ';
        cout << endl;
    }
    
    }
}