Cod sursa(job #2680227)

Utilizator BarbumateiBarbu Matei Barbumatei Data 2 decembrie 2020 23:33:45
Problema Lowest Common Ancestor Scor 60
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.74 kb
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>

#include <cstddef>
#include <utility>
#include <vector>
#include <stack>
#include <map>

#define debug 0

using namespace std;

class dijoint_set {
  private:
    int size;
    vector<int> parent;
    vector<int> rank;

  public:
    dijoint_set(int size) {
      parent.resize(size, -1);
      rank.resize(size);
    }

    int get_size() {
      return size;
    }

    vector<int> get_parent_repr() {
      return parent;
    }

    void make_set(int node) {
      parent[node] = node;
      rank[node] = 1;
    }

    int find(int node) {
      int root = node, aux;
      while (root != parent[root]) {
        root = parent[root];
      }

      while (node != root) {
        aux = parent[node];
        parent[node] = root;
        node = aux;
      }

      return root;
    }

    void union_set(int x, int y) {
      int dadx = find(x), dady = find(y);
      if (dadx == dady) {
        return;
      }

      if (rank[dadx] > rank[dady]) {
        parent[dady] = dadx;
      }
      else {
        parent[dadx] = dady;
      }

      if (rank[dadx] == rank[dady]) {
        rank[dady]++;
      }
    }

    void set_ancestors(int node, int ancestor) {
      int root = find(node);
      if (root == find(ancestor)) {
        parent[root] = ancestor;
        parent[ancestor] = ancestor;
        rank[ancestor] = rank[root] + 1;
      }
    }
};

/* OLCA(u)
    MakeSet(u)
    u.ancestor := u
    for each v in u.children do
        TarjanOLCA(v)
        Union(u, v)
        Find(u).ancestor := u
    u.color := black
    for each v such that {u, v} in P do
        if v.color == black then
            print "Tarjan's Lowest Common Ancestor of " + u +
                  " and " + v + " is " + Find(v).ancestor + "." */

/* void offline_lcaconst(int node, vector<vector<int>> &graph,
                     const vector<vector<int>> &questions,
                     dijoint_set &forest) {
  size_t i;
  int son, local_root;
  forest.make_set(node);
  for (i = 1; i <= graph[node].size(); i++) {
    son = graph[node][i];
    offline_lcaconst(son, graph, questions, forest);
    forest.union_set(node, son);
     local_root = forest.find(node);
      forest
    */
  /*}


}*/

static pair<int, int> order_pair(int a, int b) {
  return make_pair(min(a, b), max(a, b));
}

static pair<int, int> order_pair(pair<int, int> p) {
  return make_pair(min(p.first, p.second), max(p.first, p.second));
}

vector<int> lca(const vector<vector<int>> &graph,
                     const vector<pair<int, int>> &queries) {
  vector<vector<int>> tree(graph);
  vector<vector<int>> questions(graph.size());
  vector<int> answers(queries.size());
  stack<int> st;
  map<pair<int, int>, int> results;
  pair<int, int> query_pair;
  vector<bool> visited(graph.size(), false);

  size_t i;
  int node, son;

  dijoint_set forest(graph.size());

  for (i = 0; i < queries.size(); i++) {
    int a = queries[i].first, b = queries[i].second;
    questions[a].push_back(b);
    questions[b].push_back(a);
  }

  for (i = 0; i < graph.size(); i++) {
    forest.make_set(i);
    // visited[i] = false;
  }

  st.push(0);
  while (!st.empty()) {
    node = st.top();

    if (debug)
      printf("%d\n", node + 1);
    // if node has no more unprocessed sons
    if (tree[node].size() == 1) {
      visited[node] = true;

      // iterate through the list of questions
      for(const auto& other: questions[node]) {
        query_pair = order_pair(node, other);

        // if we have note processed any answers for this query
        if (visited[other] && results.find(query_pair) == results.end()) {
          results[query_pair] = forest.find(other);
          if (debug)
          printf("Query: %d %d %d\n", query_pair.first + 1, query_pair.second + 1, results[query_pair] + 1);
        }
      }

      // unite node with his father
      if (debug)
      printf("unite\n");
      forest.union_set(node, tree[node][0]);
      if (debug)
      printf("set_an\n");
      // set the ancestor of node's dijoint set to be the node's parent
      forest.set_ancestors(node, tree[node][0]);

      // finished processing node
      st.pop();
    }
    else {
      // apply the recursive algorithm on the first son
      son = tree[node].back();
      if (debug)
      printf("node: %d son:%d\n", node + 1, son + 1);
      tree[node].pop_back();
      st.push(son);
    }
  }

  for (i = 0; i < queries.size(); i++) {
    query_pair = order_pair(queries[i]);
    answers[i] = results[query_pair];
  }

  return answers;
}


using namespace std;

void read_data(const char *in_file, vector<vector<int>> &graph,
               vector<pair<int, int>> &queries) {
  unsigned int N, M, i, j, k;

  //if (in_file != NULL) {
    if (freopen("lca.in", "rt", stdin) == NULL) {
      exit(1);
    }
  //}

  scanf("%u%u", &N, &M);
  graph.resize(N, vector<int>(1));

  for (i = 2; i <= N; i++) {
    scanf("%u", &j); // we read the father of node i
    // because we index at 0 we read j-1 is the father of i - 1
    graph[i - 1][0] = j - 1;
    graph[j - 1].push_back(i - 1);
  }

  for (i = 0; i < M; i++) {
    scanf("%u%u", &j, &k);
    queries.push_back(make_pair(j - 1, k - 1));
  }

  fclose(stdin);
}

void print_data(const char *out_file, const vector<int> &answers) {
  unsigned int i;

  //if (out_file != NULL) {
    if (freopen("lca.out", "wt", stdout) == NULL) {
      exit(2);
    }
  //}

  for (i = 0; i < answers.size(); i++) {
    printf("%d\n", answers[i] + 1);
  }

  fclose(stdout);
}

int main(int argc, char *argv[]) {
  vector<vector<int>> graph;
  vector<pair<int, int>> queries;
  vector<int> answers;

  if (argc > 3) {
    perror("Please use maximum two files\n");
    return -1;
  }

  read_data(argv[1], graph, queries);
  answers = lca(graph, queries);
  print_data(argv[2], answers);

  return 0;
}