Cod sursa(job #3207618)

Utilizator redstonegamer22Andrei Ion redstonegamer22 Data 26 februarie 2024 16:26:24
Problema Stramosi Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.33 kb
#include <bits/stdc++.h>

using namespace std;

#ifndef LOCAL
ifstream in("stramosi.in");
ofstream out("stramosi.out");
#define cin in
#define cout out
#endif // LOCAL

const int nmax = 25e4 + 7;
const int exp_max = 20;
int parinte[nmax];

// functia saritura_p2 in conceptele programarii functionale (nu prea se aplica la olimpiada)
// este o functie PURA -> memoizabila
// 1. nu are efecte secundare (nu schimba variabile globale)
// 2. daca primeste acelasi input, mereu ofera inapoi acelasi output
// Observatia Importanta! Este o functie recursiva care se apeleaza pe sine
// --> Daca o memoizam, va merge in O(1) amortizat!

int memo[nmax][exp_max];

int saritura_p2(int node, int exp) {
	// face o saritura de marime 2^exp in sus, pornind de la nodul nod

	const int speed = 3;

	// Implementarea 1. Naiv
	if(speed == 1) {
		for(int rep = 0; rep < (1 << exp); rep++) {
			node = parinte[node];
		}
		return node;
	}

	if(speed == 2) {
		if(exp == 0) {
			// saritura de marime 2^0 = 1 inseamna doar parinte[node]
			return parinte[node];
		}

		// altfel, eu pot sa fac o saritura de marime 2^exp, din 2 sarituri mai mici
		// fiecare de marimea 2 ^ (exp - 1)
		node = saritura_p2(node, exp - 1);
		node = saritura_p2(node, exp - 1);

		return node;
	}

	if(speed == 3) {
		if(exp == 0) {
			return parinte[node];
		}
		if(memo[node][exp] != -1) { // valoarea initiala = -1
			return memo[node][exp];
		}

		int init_node = node;
		node = saritura_p2(node, exp - 1);
		node = saritura_p2(node, exp - 1);
		memo[init_node][exp] = node;

		return node;
	}
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	for(int i = 0; i < nmax; i++) {
		for(int j = 0; j < exp_max; j++) {
			memo[i][j] = -1;
		}
	}

	int n, q; cin >> n >> q;
	for(int i = 1; i <= n; i++) {
		cin >> parinte[i];
	}

	// bottom-up DP
	for(int exp = 0; exp < exp_max; exp++) {
		for(int node = 0; node < nmax; node++) {
			if(exp == 0) memo[node][exp] = parinte[node];
			else {
				memo[node][exp] = memo[memo[node][exp - 1]][exp - 1];
			}
		}
	}

	while(q--) {
		int node, pas;
		cin >> node >> pas;

		// Cum spargem pas in puteri de 2?
		const int exp_max = 18;
		for(int exp = 0; exp <= exp_max; exp++) {
			// verific daca bitul de 1 care corespunde lui 2^exp este setat in pas

			if(pas & (1 << exp)) {
				node = saritura_p2(node, exp);
			}
		}

		cout << node << '\n';
	}
}