Cod sursa(job #2093607)

Utilizator Stefan_RaduStefan Radu Stefan_Radu Data 24 decembrie 2017 10:54:50
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.05 kb
#include <cstdio>
#include <vector>
#include <cmath>
#include <stack>

using namespace std;

class In_Pars {

public:
  In_Pars(const char *name) {
    in = fopen(name, "r");
    buff = new char[4096];
    index = 4095;
  }

  void operator >> (int &n) {
    char c;
    c = read_char();
    while (c < '0' or c > '9') {
      c = read_char();
    }

    n = 0;
    while (c >= '0' and c <= '9') {
      n = n * 10 + c - '0';
      c = read_char();
    }
  }

private:
  FILE *in;
  char *buff;
  int index;

  char read_char() {
    index ++;
    if (index == 4096) {
      index = 0;
      fread(buff, 1, 4096, in);
    }
    return buff[index];
  }
};

In_Pars in("lca.in");
  
class Hpd {
public:
 
  Hpd() { 
    in >> n;
    in >> m;
    _chain.resize(n + 1);
    _level.resize(n + 1);
    _chain_lvl.resize(n + 1);
    _tata.resize(n + 1);
    _chain_of.resize(n + 1);
    _weight.resize(n + 1);
    _gr.resize(n + 1);
    
    freopen("lca.out", "w", stdout);
    for (int i = 2; i <= n; i ++) {
      in >> _tata[i];
      _gr[_tata[i]].push_back(i);
    }
 
    _Init();
    _Set_lvl();
    _Init_dp();
  }
 
  void Solve() {
 
    int x, y;
    for (int i = 1; i <= m; i ++) {
       
      in >> x;
      in >> y;
      if (_chain_lvl[x] > _chain_lvl[y]) {
        swap(x, y);
      }
 
      int dif = _chain_lvl[y] - _chain_lvl[x];
      int bit = 0;
      while (dif) {
        if (dif & 1) {
          y = _dp[bit][y];
        }
 
        dif >>= 1;
        bit += 1;
      }
      
     for (int i = lim; i >= 0; i --) {
        if (_chain_of[_dp[i][x]] != _chain_of[_dp[i][y]]) {
          x = _dp[i][x];
          y = _dp[i][y];
        }
      }
 
      if (_chain_of[x] != _chain_of[y]) {
        x = _dp[0][x];
        y = _dp[0][y];
      }
 
      if (_level[x] >= _level[y]) {
        printf("%d\n", y);
      }
      else {
        printf("%d\n", x);
      }
    }
  }
 
private:
 
  int n, m, max_chain_nr, lim, max_chain_lvl;
  vector < int > _level, _chain_of, _weight, _tata, _chain_lvl;
  vector < vector < int > > _chain, _gr, _dp;
  stack < pair < int, int > > st;

  void _Init() {

    st.push({1, 0});
    _level[1] = 1;
    max_chain_nr = 0;
    for (int i = 1; i <= n; i ++) {
      _weight[i] = 1;
    }
  
    while (not st.empty()) {
      
      auto cur = st.top();
      st.pop();
      if (not _gr[cur.first].size()) {
        _chain[++ max_chain_nr].push_back(cur.first);
        _chain_of[cur.first] = max_chain_nr;
      }
      else if (cur.second + 1 <= (int) _gr[cur.first].size()) {
        int next_node = _gr[cur.first][cur.second];
        _level[next_node] = _level[cur.first] + 1;
        st.push({cur.first, cur.second + 1});
        st.push({next_node, 0});
      }
      else {
        int best = 0;
        for (auto x : _gr[cur.first]) {
          _weight[cur.first] += _weight[x];
          if (_weight[x] > _weight[best]) {
            best = x;
          }
        }

        _chain[_chain_of[best]].push_back(cur.first);
        _chain_of[cur.first] = _chain_of[best];
      }
    }
  }
 
  void _Set_lvl() {
     
    st.push({1, 0});
    _chain_lvl[1] = 1;
    max_chain_lvl = 1;
    while (not st.empty()) {

      auto cur = st.top();
      st.pop();
      max_chain_lvl = max(max_chain_lvl, _chain_lvl[cur.first]);
      if (cur.second + 1 <= (int) _gr[cur.first].size()) {
        int next_node = _gr[cur.first][cur.second];
        st.push({cur.first, cur.second + 1});
        if (_chain_of[next_node] != _chain_of[cur.first]) {
          _chain_lvl[next_node] = _chain_lvl[cur.first] + 1;
        }
        else {
          _chain_lvl[next_node] = _chain_lvl[cur.first];
        }
        st.push({next_node, 0});
      }
    }
  }

  void _Init_dp() {
    
    lim = log2(max_chain_lvl);
    _dp.resize(lim + 1);
    for (auto &x : _dp) {
      x.resize(n + 1);
    }
 
    for (int i = 1; i <= n; i ++) {
      _dp[0][i] = _tata[_chain[_chain_of[i]].back()];
    }
 
    for (int i = 1; i <= lim; i ++) {
      for (int j = 1; j <= n; j ++) {
        _dp[i][j] = _dp[i - 1][_dp[i - 1][j]];
      }
    }
  }
};


int main() {
  
  Hpd *H = new Hpd();
  H -> Solve();
}