Cod sursa(job #3235376)

Utilizator GeutzzuBorozan George Geutzzu Data 17 iunie 2024 15:05:36
Problema Lowest Common Ancestor Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 7.2 kb

#include <vector>
#include <queue>
#include <algorithm>
#include <fstream>
#include <cmath>

using namespace std;

struct node {
    int valoare;
    node* next;
};

void adaugareInceput(node*& head, node*& last, int x)
{
    node* element = new node;
    element->valoare = x;
    ///element->next=NULL;
    element->next = head; //devine NULL daca head este NULL
    if (head == NULL) //separat cazul in care lista este vida-> se actualizeaza si last
        last = element;
    head = element;

}

void adaugareFinal(node*& head, node*& last, int x)
{
    node* element = new node;
    element->valoare = x;
    element->next = NULL;
    if (head == NULL) //separat cazul in care lista este vida
        head = element;
    else last->next = element;
    last = element;
}

void stergereInceput(node*& head, node*& last)
{
    if (head == NULL)
        return;
    node* p = head;
    head = head->next;
    delete p;
    if (head == NULL) //cazul cand lista ramane vida- se modifica si last
        last = NULL;

}

void stergereFinal(node*& head, node*& last)
{
    node* p = head;
    if (head == NULL)
        return;
    if (head == last) //lista cu un element, echivalent cu head->next==NULL
    {
        delete head;
        head = NULL;
        last = NULL;
        return;
    }
    while (p->next->next) //ne pozitionam pe penultimul element pentru a il sterge pe ultimul
    {
        p = p->next;
    }
    delete p->next;
    last = p;
    p->next = NULL;
}

void inserare(node*& head, node*& last, int x, int poz)
{
    if (poz == 0)
    {
        adaugareInceput(head, last, x);
        return;
    }
    /*!!separat cazul de lista vida in care vrem sa inseram pe pozitie>0*/
    if (head == NULL)
        return;
    int cnt = 0;
    node* p = head;
    while (cnt < poz - 1) //ne pozitionam inainte sa inseram, puteam folosi si for
    {
        p = p->next;
        if (p == NULL) //daca am iesit din lista poz este prea mare->nu inseram
        {
            return;
        }
        cnt++;
    }
    node* q = new node;
    q->valoare = x;
    q->next = NULL;
    q->next = p->next;
    p->next = q;
    if (q->next == NULL) //am adaugat la final daca dupa noul nod nu urmeaza alt nod
        last = q;

}

void stergere(node*& head, node*& last, int poz)
{
    if (poz == 0)
    {
        stergereInceput(head, last);
        return;
    }
    /*!!separat cazul de lista vida */
    if (head == NULL)
        return;
    int cnt = 0;
    node* p = head;
    while (cnt < poz - 1) //ne pozitionam tot inaine de elementul de sters
    {
        p = p->next;
        if (p == NULL) //daca am iesit din lista poz este prea mare->nu inseram
        {
            return;
        }
        cnt++;
    }
    //suntem pozitionati inainte de poz
    //stergem p->next, daca exista
    if (p->next) {
        node* q;
        q = p->next; //elementul care va fi sters
        p->next = p->next->next;
        delete q;
        if (p->next == NULL)
            last = p;
    }
}

void afisare(node* head)
{
    node* p = head;
    while (p)
    {
        cout << p->valoare << ' ';
        p = p->next;
    }
    cout << endl;
}

struct Compare {
    bool operator()(pair<int, int> a, pair<int, int> b) {

        return a.first > b.first; // This will create a min heap
    }

	bool operator()(vector <int> v1, vector<int> v2) {

		if (v1[0] == v2[0]) {

			return v1[1] < v2[1];
		}
		else return v1[0] < v2[0];

	}

};


node* mergeKLists(vector<node*>& lists) {
    priority_queue<pair<int, int> , vector<pair<int, int> >, Compare > pq; /// value and list index

    node* rez = nullptr;
    node* last = nullptr;

	for (int i = 0; i < lists.size(); i++) {
        if (lists[i] != nullptr) {
            pq.push({ lists[i]->valoare, i });
        }
	}

    while (!pq.empty()) {
        pair<int, int> currVal = pq.top();
        pq.pop();
        adaugareFinal(rez, last, currVal.first);
        if (lists[currVal.second]->next != nullptr) {
            lists[currVal.second] = lists[currVal.second]->next;
            pq.push({ lists[currVal.second]->valoare, currVal.second });
        }

    }

    return rez;

}

int minGroups(vector<vector<int>>& intervals) {
    priority_queue<int, vector<int>, greater<int>> pq;

    sort(intervals.begin(), intervals.end(), Compare());


	for (int i = 0; i < intervals.size(); i++) {
        if (!pq.empty() && pq.top() < intervals[i][0])
            pq.pop();
        pq.push(intervals[i][1]);

	}

	return pq.size();
    
}
const int NMAX = 100005;
const int LMAX = 20;

int k, n, m;
int nivel[NMAX << 1], euler[NMAX << 1], prima_apar[NMAX]; //euler tur- 2*nr muchii

int rmq[NMAX << 1][20];

node* G[NMAX];

node* lastG[NMAX];


void parcurg(int nod, int niv_curent) {
    k = k + 1; //// index pentru reprezentarea euler
	euler[k] = nod; /// nodul curent se pune la pozitia k in turul euler
	nivel[k] = niv_curent; /// nivelul nodului curent in arbore
	prima_apar[nod] = k; /// prima aparitie a nodului in turul euler

	node* p = G[nod]; 
	while (p != NULL) { /// parcurgem fii nodului actual (descendentii sai)
		parcurg(p->valoare, niv_curent + 1); /// apelam recursiv parcurgerea pentru fiecare fiu

        /// la intoarcerea din recursivitate adaugam "de jos in sus" in turul euler
		k = k + 1; 
        euler[k] = nod;
        nivel[k] = niv_curent;
		p = p->next; /// mergem la urmatorul descendent
    }
}

void prepr_rmq() {

    for (int i = 0; i <= k; i++)
        rmq[i][0] = i; 

    for (int j = 1; (1 << j) <= k; j++) /// 1 << j = 2^j
        for (int i = 0; i + (1 << j) - 1 < k; i++) /// i + 2^j - 1 < n <=> i < n - 2^j + 1
        {
            int l = 1 << (j - 1); /// 2^(j-1)

			if (nivel[rmq[i][j - 1]] < nivel[rmq[i + l][j - 1]])
				rmq[i][j] = rmq[i][j - 1];
			else
				rmq[i][j] = rmq[i + l][j - 1];

            ///rmq[i][j] = min(rmq[i][j - 1], rmq[i + l][j - 1]); /// rmq[i][j] = the minimum of the interval [i, i + 2^(j-1) - 1] and the minimum of the interval [i + 2^(j-1), i + 2^j - 1]
            /// it consists of the minimum of the interval [i, i + 2^(j-1) - 1] and the minimum of the interval [i + 2^(j-1), i + 2^j - 1]
        }
}

int query(int x, int y) {
    int k = log2(y - x + 1); /// 2^k <= y - x + 1
    int l = 1 << k; /// 2^k

	if (nivel[rmq[x][k]] < nivel[rmq[y - l + 1][k]])
		return euler[rmq[x][k]];
	else
		return euler[rmq[y - l + 1][k]];

    /// return min(rmq[x][k], rmq[y - l][k]); /// the minimum of the interval [x, y] is the minimum of the interval [x, x + 2^k - 1] and the minimum of the interval [y - 2^k + 1, y]
}


int main() {

	ifstream cin("lca.in");
	ofstream cout("lca.out");

    int x;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        G[i] = lastG[i] = NULL;

    for (int i = 2; i <= n; i++) {
        cin >> x;
        adaugareFinal(G[x], lastG[x], i);
    }

    k = -1;
    parcurg(1, 0);


    prepr_rmq();


    for (int i = 0; i < m; i++) {

        int x, y;
        cin >> x >> y;

		if (prima_apar[x] > prima_apar[y])
			swap(x, y);

        cout << query(prima_apar[x] , prima_apar[y] ) << endl;

    }
}