Commit ef6b14c1 authored by Konstantinos Agiannis's avatar Konstantinos Agiannis

Κώδικες και διαφάνειες LCA 2020

parent 827dcd7c
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
vector<vector<long>> adj, T;
vector<long> par;
vector<long> st, en;
long timer = 0;
long max_height;
void preprocess(long u) {
T[u][0] = par[u];
for (int i = 1; i <= max_height; ++i)
T[u][i] = T[T[u][i-1]][i-1];
st[u] = ++timer;
for (auto v : adj[u]) {
preprocess(v);
}
en[u] = ++timer;
}
bool is_ancestor(long u, long v) {
return st[u] <= st[v] && en[v] <= en[u];
}
long find_lca(long u, long v) {
if (is_ancestor(u, v)) return u;
if (is_ancestor(v, u)) return v;
for (long i = max_height; i >= 0; --i) {
if (!is_ancestor(T[u][i], v))
u = T[u][i];
}
return T[u][0];
}
void clear() {
adj.clear();
par.clear();
st.clear();
en.clear();
T.clear();
}
void reset(long N) {
par.resize(N+1);
adj.resize(N+1);
st.resize(N+1);
en.resize(N+1);
timer = 0;
max_height = ceil(log2(N));
T.resize(N + 1, vector<long>(max_height + 1));
}
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;
}
}
par[root] = root;
// Pre-process.
preprocess(root);
// 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;
}
#include <cstdio>
#include <vector>
using namespace std;
// Τα παιδιά του κάθε κόμβου.
vector<vector<long>> adj;
// Το βάθος του κάθε κόμβου.
vector<long> d;
// Ο πατέρας του κάθε κόμβου.
vector<long> par;
long find_lca(long a, long b) {
if (d[a] < d[b]) swap(a, b);
// Ανεβάζουμε τον χαμηλότερο μέχρι να
// έρθει στο επίπεδο του ψηλότερου.
while (d[a] > d[b]) a = par[a];
// Τους ανεβάζουμε κατά ένα επίπεδο μέχρι
// να φτάσουν στον ίδιο κόμβο.
while (a != b) {
a = par[a];
b = par[b];
}
return a;
}
void compute_depth_array(long u, long par_depth) {
d[u] = par_depth + 1;
for (auto v : adj[u]) {
compute_depth_array(v, d[u]);
}
}
void clear() {
adj.clear();
d.clear();
par.clear();
}
int main() {
long T;
scanf("%ld", &T);
for (long case_id = 1; case_id <= T; ++case_id) {
clear();
long N;
scanf("%ld", &N);
par.resize(N+1);
adj.resize(N+1);
d.resize(N+1);
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_depth_array(root, 0);
// 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;
}
#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;
}
#include <cstdio>
#include <vector>
using namespace std;
// Τα παιδιά του κόμβου.
vector<vector<long>> adj;
// Το βάθος ενός κόμβου στο δένδρο και ο πατέρας του.
vector<long> d, par;
// Όπως ορίστηκαν πριν.
vector<long> idx;
vector<vector<long>> v;
// Αν η ακμή που συνδέει το κόμβο με τον πατέρα του είναι heavy.
vector<bool> is_heavy;
// Το ID του τελευταίου μονοπατιού που δημιουργήσαμε.
long cur_heavy_id;
long compute_hld(long u, long par_depth) {
d[u] = par_depth + 1;
// Για τα φύλλα ξεκινάμε ένα καινούργιο heavy μονοπάτι.
if (adj[u].size() == 0) {
heavy_path_id[u] = ++cur_heavy_id;
v[heavy_path_id[u]].push_back(u);
idx[u] = 0;
return 1;
}
// Δημιουργούμε αναδρομικά τα μονοπάτια των παιδιών.
// Βρίσκουμε το παιδί με το μεγαλύτερο υποδένδρο και επεκτείνουμε
// το δικό του μονοπάτι.
long subtree_size = 0, max_subtree_size = 0, cur_heavy_edge;
for (auto v : adj[u]) {
long cur_subtree_size = compute_hld(v, d[u]);
subtree_size += cur_subtree_size;
if (cur_subtree_size > max_subtree_size) {
max_subtree_size = cur_subtree_size;
cur_heavy_edge = v;
}
}
// Μαρκάρουμε την ακμή ως heavy και ανανεώνουμε τους πίνακες.
is_heavy[cur_heavy_edge] = true;
long path_id = heavy_path_id[cur_heavy_edge];
heavy_path_id[u] = path_id;
idx[u] = v[path_id].size();
v[path_id].push_back(u);
return subtree_size;
}
long find_kth_ancestor(long x, long k) {
while (k > 0) {
if (is_heavy[x]) {
if (k + idx[x] < v[heavy_path_id[x]].size()) {
// (1) Πρόγονος εντός heavy μονοπατιού
return v[heavy_path_id[x]][k + idx[x]];
} else {
// (2) Πρόγονος εκτός heavy μονοπατιού
k -= (v[heavy_path_id[x]].size() - idx[x] - 1);
x = v[heavy_path_id[x]].back();
}
} else {
// (3) light ακμή
x = par[x];
--k;
}
}
return x;
}
long find_lca(long a, long b) {
while (a != b) {
if (heavy_path_id[a] == heavy_path_id[b]) {
// Αφού είναι στο ίδιο heavy μονοπάτι, επιστρέφουμε
// αυτόν που είναι ψηλότερα.
return d[a] < d[b] ? a : b;
}
long a_next =
is_heavy[a] ? v[heavy_path_id[a]].back() : par[a];
long b_next =
is_heavy[b] ? v[heavy_path_id[b]].back() : par[b];
// Μετακινούμε τον χαμηλότερο.
if (d[a_next] > d[b_next]) a = a_next;
else b = b_next;
}
return a;
}
void clear() {
adj.clear();
d.clear();
par.clear();
v.clear();
idx.clear();
is_heavy.clear();
heavy_path_id.clear();
cur_heavy_id = 0;
}
void reset(long N) {
par.resize(N+1);
adj.resize(N+1);
d.resize(N+1);
v.resize(N+1);
idx.resize(N+1);
is_heavy.resize(N+1);
heavy_path_id.resize(N+1);
}
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_hld(root, 0);
// 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_kth_ancestor(a, b));
}
}
return 0;
}
#include <cstdio>
#include <vector>
using namespace std;
// Τα παιδιά του κάθε κόμβου.
vector<vector<long>> adj;
// Το βάθος του κάθε κόμβου.
vector<long> d;
// Ο πατέρας του κάθε κόμβου.
vector<long> par;
// Queries ανα κόμβο (μαζί με το ID τους).
vector<vector<pair<long, long>>> queries;
// Ο πρόγονος όλου του DSU set.
vector<long> ancestor;
// Αν έχουμε επισκεφτεί έναν κόμβο.
vector<bool> visited;
// Απάντηση για το i-οστό query.
vector<long> answer;
// DSU πράγματα.
vector<long> dsu_size, dsu_par;
void make_sets(long N) {
for (long v = 0; v < N; ++v) {
dsu_par[v] = v;
dsu_size[v] = 1;
}
}
long find_set(long v) {
if (v == dsu_par[v]) return v;
return dsu_par[v] = find_set(dsu_par[v]);
}
void union_sets(long a, long b) {
a = find_set(a);
b = find_set(b);
if (a != b) {
if (dsu_size[a] < dsu_size[b])
swap(a, b);
dsu_par[b] = a;
dsu_size[a] += dsu_size[b];
}
}
void dfs(long v) {
visited[v] = true;
// Θέτουμε τον πρόγονο του set του.
ancestor[v] = v;
for (long u : adj[v]) {
dfs(u);
// Αφού τελειώσουμε με το παιδί
// το ενώνουμε στο set του πατέρα.
union_sets(v, u);
// Σιγουρευόμαστε ότι ο πρόγονος
// του set είναι v.
ancestor[find_set(v)] = v;
}
for (auto other_and_idx : queries[v]) {
// Αν δεν έχουμε επισκεφτεί τον άλλον κόμβο
// δεν μπορούμε να απαντήσουμε το query.
if (visited[other_and_idx.first]) {
answer[other_and_idx.second]
= ancestor[find_set(other_and_idx.first)];
}
}
}
void clear() {
adj.clear();
d.clear();
par.clear();
dsu_par.clear();
dsu_size.clear();
visited.clear();
ancestor.clear();
queries.clear();
answer.clear();
}
void reset(long N) {
par.resize(N+1);
adj.resize(N+1);
d.resize(N+1);
dsu_size.resize(N+1);
dsu_par.resize(N+1);
visited.resize(N+1);
ancestor.resize(N+1);
queries.resize(N+1);
make_sets(N+1);
}
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+1);
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;
}
}
// Answer queries.
long Q;
scanf("%ld", &Q);
printf("Case %ld:\n", case_id);
for (long q = 0; q < Q; ++q) {
long a, b;
scanf("%ld%ld", &a, &b);
queries[a].push_back({b, q});
queries[b].push_back({a, q});
}
answer.resize(Q);
dfs(root);
for (long q = 0; q < Q; ++q) {
printf("%ld\n", answer[q]);
}
}
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment