Cod sursa(job #1183257)

Utilizator valentin.harsanValentin Harsan valentin.harsan Data 8 mai 2014 18:10:54
Problema Lowest Common Ancestor Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 4.83 kb
#include<iostream>
#include<fstream>
#include<vector>
#include<algorithm>
using namespace std;

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

const int N = 101000;
const int SIZ = 9;

int n, m, e[2 * N], nr, cs[N];
int minLeft[1<<SIZ][SIZ], minRight[1<<SIZ][SIZ], pozminLeft[1<<SIZ][SIZ], pozminRight[1<<SIZ][SIZ];
int niv[N];
vector<int> v[N];

int valNr1[N], tip[N], pozB[N];

void eul(int nod) {
    e[++nr] = nod;
    cs[nod] = nr;

    for(vector<int>::iterator it = v[nod].begin(); it != v[nod].end(); ++it) {
        niv[*it] = niv[nod] + 1;

        eul(*it);
        e[++nr] = nod;
    }
}

void precalc1() {
    int i, j;

    for(i = 0; i < (1<<SIZ); ++i) {
        int boss = 0;

        for(j = 0; j < SIZ; ++j) {
            if(i & (1<<j))
                ++boss;
            else
                --boss;

            minLeft[i][j] = boss;
            pozminLeft[i][j] = j;

            if(j && minLeft[i][j - 1] > boss) {
                minLeft[i][j] = minLeft[i][j - 1];
                pozminLeft[i][j] = pozminLeft[i][j - 1];
            }
        }

        boss = 0;

        for(j = SIZ - 1; j >= 0; --j) {
            if(i & (1<<j))
                ++boss;
            else
                --boss;

            minRight[i][j] = boss;
            pozminRight[i][j] = j;

            if(j != SIZ - 1 && minRight[i][j + 1] > boss) {
                minRight[i][j] = minRight[i][j + 1];
                pozminRight[i][j] = pozminRight[i][j + 1];
            }
        }

    }
}

void precalc2() {
    int i, j;

    for(i = 1; i <= nr; ++i) {
        if(i % 10 == 1) {
            pozB[i] = -1;

            int ti = 0;
            valNr1[i] = niv[e[i]];

            for(j = i + 1; j < i + 10; ++j)
                if(niv[j] > niv[j - 1])
                    ti |= (1<<(j - i - 1));
        }
        else {
            valNr1[i] = valNr1[i - 1];
            tip[i] = tip[i - 1];
            pozB[i] = pozB[i - 1] + 1;
        }
    }

    for(i = 1; i <= nr; ++i)
        if(pozB[i] == -1)
            pozB[i] = 0;
}

int rmq[15][N], elMin[15][N], p2[N];

void precalc3() {
    int i, j;
    int nu = 0;

    for(i = 2; i < N; ++i)
        p2[i] = p2[i / 2] + 1;

    for(i = 1; i <= nr; ++i) {

        if(i % 10 == 1) {
            int nivv = 1000000, nodd;

            for(j = i; j < i + 10; ++j) {
                if(niv[e[j]] < nivv) {

                    nodd = e[j];
                    nivv = niv[e[j]];
                }
            }

            rmq[0][++nu] = nivv;
            elMin[0][nu] = nodd;
        }
    }

    for(i = 1; i < 15; ++i) {

        for(j = 1; j <= nr - (1<<i); ++j) {
            int l = (1<<(i - 1));

            if(rmq[i - 1][j] < rmq[i - 1][j + l]) {

                rmq[i][j] = rmq[i - 1][j];
                elMin[i][j] = elMin[i - 1][j];
            }
            else {

                rmq[i][j] = rmq[i - 1][j + l];
                elMin[i][j] = elMin[i - 1][j + l];
            }
        }
    }
}

int lca(int nod1, int nod2) {

    int nivmin, elmin;
    if(niv[nod1] > niv[nod2]) {
        nivmin = niv[nod2];
        elmin = nod2;
    }
    else {
        nivmin = niv[nod1];
        elmin = nod1;
    }

    if(cs[nod1] > cs[nod2])
        swap(nod1, nod2);

    //yolo
    if(cs[nod2] - cs[nod1] <= 10) {
        int nmin = 10000000, ell;

        for(int i = cs[nod1]; i <= cs[nod2]; ++i) {

            if(niv[e[i]] < nmin) {
                nmin = niv[e[i]];
                ell = e[i];
            }
        }
        return ell;
    }
    //

    nod1 = cs[nod1];
    nod2 = cs[nod2];

    if(valNr1[nod1] + minRight[tip[nod1]][pozB[nod1]] < nivmin) {

        nivmin = valNr1[nod1] + minRight[tip[nod1]][pozB[nod1]];
        elmin = e[pozminRight[tip[nod1]][pozB[nod1]]];
    }

    if(nod2 % 10 != 1 && valNr1[nod2] + minLeft[tip[nod2]][pozB[nod2]] < nivmin) {

        nivmin = valNr1[nod2] + minLeft[tip[nod2]][pozB[nod2]];
        elmin = e[pozminLeft[tip[nod2]][pozB[nod2]]];
    }

    //calc3

    int poz1, poz2;

    poz1 = (nod1 - 1) / 10 + 2;
    poz2 = (nod2 - 1) / 10 + 2;

    int l = p2[poz2 - poz1];

    if(rmq[l][poz1] < nivmin) {
        nivmin = rmq[l][poz1];
        elmin = elMin[l][poz1];
    }

    if(rmq[l][poz2 - (1<<l) + 1] < nivmin) {
        nivmin = rmq[l][poz2 - (1<<l) + 1];
        elmin = elMin[l][poz2 - (1<<l) + 1];
    }

    return elmin;
}

int main() {
    int i;

    in >> n >> m;

    for(i = 1; i < n; ++i) {
        int a;
        in >> a;
        v[a].push_back(i + 1);
    }

    eul(1);

    precalc1();
    precalc2();
    precalc3();

    for(i = 1; i <= m; ++i) {
        int c1, c2;
        in >> c1 >> c2;

        out << lca(c1, c2) << "\n";
    }

    return 0;
}