Cod sursa(job #3245053)

Utilizator MagicantPlusIuoras Andrei MagicantPlus Data 27 septembrie 2024 08:34:07
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.88 kb
#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define ull unsigned ll
#define vec vector
#define flist forward_list
#define um unordered_map
#define us unordered_set
#define prioq priority_queue
#define all(x) x.begin(), x.end()
#define pb push_back
#define pf push_front
#define fi first
#define se second
#define mp make_pair
#define mt make_tuple
#define ld long double
#define pll pair<ll, ll>

#define LL_MAX LLONG_MAX
#define LL_MIN LLONG_MIN
#define ULL_MAX ULLONG_MAX
#define ULL_MIN 0
#define LD_MAX LDBL_MAX
#define LD_MIN LDBL_MIN

#define nl '\n'

#define vv(type, name, n, ...) vector<vector<type>> name(n, vector<type>(__VA_ARGS__))
#define vvv(type, name, n, m, ...)                                                                                     \
    vector<vector<vector<type>>> name(n, vector<vector<type>>(m, vector<type>(__VA_ARGS__)))

// https://trap.jp/post/1224/
#define rep1(n) for(ll i=0; i<(ll)(n); ++i)
#define rep2(i,n) for(ll i=0; i<(ll)(n); ++i)
#define rep3(i,a,b) for(ll i=(ll)(a); i<(ll)(b); ++i)
#define rep4(i,a,b,c) for(ll i=(ll)(a); i<(ll)(b); i+=(c))
#define cut4(a,b,c,d,e,...) e
#define rep(...) cut4(__VA_ARGS__,rep4,rep3,rep2,rep1)(__VA_ARGS__)
#define rep1e(n) for(ll i=1; i<=(ll)(n); ++i)
#define rep2e(i,n) for(ll i=1; i<=(ll)(n); ++i)
#define rep3e(i,a,b) for(ll i=(ll)(a); i<=(ll)(b); ++i)
#define rep4e(i,a,b,c) for(ll i=(ll)(a); i<=(ll)(b); i+=(c))
#define repe(...) cut4(__VA_ARGS__,rep4e,rep3e,rep2e,rep1e)(__VA_ARGS__)
#define per1(n) for(ll i=((ll)n)-1; i>=0; --i)
#define per2(i,n) for(ll i=((ll)n)-1; i>=0; --i)
#define per3(i,a,b) for(ll i=((ll)a)-1; i>=(ll)(b); --i)
#define per4(i,a,b,c) for(ll i=((ll)a)-1; i>=(ll)(b); i-=(c))
#define per(...) cut4(__VA_ARGS__,per4,per3,per2,per1)(__VA_ARGS__)
#define per1e(n) for(ll i=((ll)n); i>=1; --i)
#define per2e(i,n) for(ll i=((ll)n); i>=1; --i)
#define per3e(i,a,b) for(ll i=((ll)a); i>=(ll)(b); --i)
#define per4e(i,a,b,c) for(ll i=((ll)a); i>=(ll)(b); i-=(c))
#define pere(...) cut4(__VA_ARGS__,per4e,per3e,per2e,per1e)(__VA_ARGS__)
#define rep_subset(i,s) for(ll i=(s); i>=0; i=(i==0?-1:(i-1)&(s)))
// #define forit(v) for (auto it = v.begin(); it != v.end(); it++)
// #define forit2(it, v) for (auto it = v.begin(); it != v.end(); it++)
// #define forrit(v) for (auto it = v.rbegin(); it != v.rend(); it++)
// #define forrit2(it, v) for (auto it = v.rbegin(); it != v.rend(); it++)

// #ifdef i_am_noob
#define bug(...) cerr << "#" << __LINE__ << ' ' << #__VA_ARGS__ << "- ", _do(__VA_ARGS__)
template<typename T> void _do(vector<vector<T>> x){cerr << "\n"; for(auto i: x) {for(auto j : i) {cerr << j << ' ';} cerr << "\n";}}
template<typename T> void _do(vector<T> x){for(auto i: x) cerr << i << ' ';cerr << "\n";}
template<typename T> void _do(set<T> x){for(auto i: x) cerr << i << ' ';cerr << "\n";}
template<typename T> void _do(unordered_set<T> x){for(auto i: x) cerr << i << ' ';cerr << "\n";}
template<typename T> void _do(T && x) {cerr << x << endl;}
template<typename T, typename ...S> void _do(T && x, S&&...y) {cerr << x << ", "; _do(y...);}
// #else
// #define bug(...) 777771449
// #endif

const ll MOD = 1e9 + 7;

const string FILENAME = "lca";
ifstream fin(FILENAME + ".in");
ofstream fout(FILENAME + ".out");

#define cin fin
#define cout fout

int n;
vector<vector<int>> adj;

int block_size, block_cnt;
vector<int> first_visit;
vector<int> euler_tour;
vector<int> height;
vector<int> log_2;
vector<vector<int>> st;
vector<vector<vector<int>>> blocks;
vector<int> block_mask;

void dfs(int v, int p, int h) {
    first_visit[v] = euler_tour.size();
    euler_tour.push_back(v);
    height[v] = h;
	
    for (int u : adj[v]) {
        if (u == p)
            continue;
        dfs(u, v, h + 1);
        euler_tour.push_back(v);
    }
}

int min_by_h(int i, int j) {
    return height[euler_tour[i]] < height[euler_tour[j]] ? i : j;
}

void precompute_lca(int root) {
    // get euler tour & indices of first occurrences
    first_visit.assign(n, -1);
    height.assign(n, 0);
    euler_tour.reserve(2 * n);
    dfs(root, -1, 0);

    // precompute all log values
    int m = euler_tour.size();
    log_2.reserve(m + 1);
    log_2.push_back(-1);
    for (int i = 1; i <= m; i++)
        log_2.push_back(log_2[i / 2] + 1);

    block_size = max(1, log_2[m] / 2);
    block_cnt = (m + block_size - 1) / block_size;

    // precompute minimum of each block and build sparse table
    st.assign(block_cnt, vector<int>(log_2[block_cnt] + 1));
    for (int i = 0, j = 0, b = 0; i < m; i++, j++) {
        if (j == block_size)
            j = 0, b++;
        if (j == 0 || min_by_h(i, st[b][0]) == i)
            st[b][0] = i;
    }
    for (int l = 1; l <= log_2[block_cnt]; l++) {
        for (int i = 0; i < block_cnt; i++) {
            int ni = i + (1 << (l - 1));
            if (ni >= block_cnt)
                st[i][l] = st[i][l-1];
            else
                st[i][l] = min_by_h(st[i][l-1], st[ni][l-1]);
        }
    }

    // precompute mask for each block
    block_mask.assign(block_cnt, 0);
    for (int i = 0, j = 0, b = 0; i < m; i++, j++) {
        if (j == block_size)
            j = 0, b++;
        if (j > 0 && (i >= m || min_by_h(i - 1, i) == i - 1))
            block_mask[b] += 1 << (j - 1);
    }

    // precompute RMQ for each unique block
    int possibilities = 1 << (block_size - 1);
    blocks.resize(possibilities);
    for (int b = 0; b < block_cnt; b++) {
        int mask = block_mask[b];
        if (!blocks[mask].empty())
            continue;
        blocks[mask].assign(block_size, vector<int>(block_size));
        for (int l = 0; l < block_size; l++) {
            blocks[mask][l][l] = l;
            for (int r = l + 1; r < block_size; r++) {
                blocks[mask][l][r] = blocks[mask][l][r - 1];
                if (b * block_size + r < m)
                    blocks[mask][l][r] = min_by_h(b * block_size + blocks[mask][l][r], 
                            b * block_size + r) - b * block_size;
            }
        }
    }
}

int lca_in_block(int b, int l, int r) {
    return blocks[block_mask[b]][l][r] + b * block_size;
}

int lca(int v, int u) {
    int l = first_visit[v];
    int r = first_visit[u];
    if (l > r)
        swap(l, r);
    int bl = l / block_size;
    int br = r / block_size;
    if (bl == br)
        return euler_tour[lca_in_block(bl, l % block_size, r % block_size)];
    int ans1 = lca_in_block(bl, l % block_size, block_size - 1);
    int ans2 = lca_in_block(br, 0, r % block_size);
    int ans = min_by_h(ans1, ans2);
    if (bl + 1 < br) {
        int l = log_2[br - bl - 1];
        int ans3 = st[bl+1][l];
        int ans4 = st[br - (1 << l)][l];
        ans = min_by_h(ans, min_by_h(ans3, ans4));
    }
    return euler_tour[ans];
}

int main()
{
	ll m;
	
	cin >> n >> m;
	
	adj.resize(n);
	
	repe(i, 2, n)
	{
		ll fath;
		cin >> fath;
		fath--;
		adj[fath].pb(i - 1);
	}
	
	precompute_lca(0);
	
	rep(m)
	{
		ll a, b;
		cin >> a >> b;
		a--;
		b--;
		
		cout << lca(a, b) + 1 << nl;
	}
	
    return 0;
}