lca_euler_tour.cc 2.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
#include <cstdio>
#include <vector>

using namespace std;

vector<vector<long>> adj;
vector<long> d;
vector<long> par;
vector<long> euler;
vector<long> st, en;


void compute_euler_array(long u, long par_depth) {
   d[u] = par_depth + 1;
   st[u] = euler.size();
   if (adj[u].empty())
      euler.push_back(u);
   for (auto v : adj[u]) {
      euler.push_back(u);
      compute_euler_array(v, d[u]);
   }
   en[u] = euler.size();
   euler.push_back(u);
}

vector<long> seg_tree;

void clear() {
   adj.clear();
   d.clear();
   par.clear();
   euler.clear();
   st.clear();
   en.clear();
   seg_tree.clear();
}

void reset(long N) {
   par.resize(N+1);
   adj.resize(N+1);
   d.resize(N+1);
   seg_tree.resize(8 * N);
   st.resize(N+1);
   en.resize(N+1);
}



void init(long n, long b, long e) {
   if (b == e) {
      seg_tree[n] = euler[b];
      return;
   }
   init(2 * n, b, (b+e)/2);
   init(2 * n + 1, (b+e)/2 + 1, e);
   if (d[seg_tree[2 * n]] < d[seg_tree[2 * n +1]]) {
      seg_tree[n] = seg_tree[2 * n];
   } else {
      seg_tree[n] = seg_tree[2 * n + 1];
   }
}

long query(long n, long b, long e, long i, long j) {
   if (i > e || j < b) return -1;
   if (i <= b && e <= j) return seg_tree[n];
   long a1 = query(2 * n, b, (b+e)/2, i, j);
   long a2 = query(2 * n + 1, (b+e)/2 + 1, e, i, j);
   if (a1 == -1) return a2;
   if (a2 == -1) return a1;
   return d[a1] < d[a2] ? a1 : a2;
}

long find_lca(long a, long b) {
   return query(1, 0, euler.size() - 1, min(st[a], st[b]), max(en[a], en[b]));
}

int main() {
   long T;
   scanf("%ld", &T);
   for (long case_id = 1; case_id <= T; ++case_id) {
   clear();
   long N;
   scanf("%ld", &N);
   reset(N);
   
   for (long i = 1; i <= N; ++i) {
      long m;
      scanf("%ld", &m);
      for (long j = 0; j < m; ++j) {
         long k;
         scanf("%ld", &k);
         adj[i].push_back(k);
         par[k] = i;
      }
   }
   // Find root.
   long root;
   for (long i = 1; i <= N; ++i) {
      if (par[i] == 0) {
         root = i;
         break;
      }
   }
   // Pre-process.
   compute_euler_array(root, 0);
   init(1, 0, euler.size() - 1);
   
   // Answer queries.
   long Q;
   scanf("%ld", &Q);
   printf("Case %ld:\n", case_id);
   while (Q--) {
      long a, b;
      scanf("%ld%ld", &a, &b);
      printf("%ld\n", find_lca(a, b));
   }
   }
   return 0;
}