Cod sursa(job #1221473)

Utilizator mihai995mihai995 mihai995 Data 20 august 2014 15:33:06
Problema Lowest Common Ancestor Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 3.73 kb
#include <fstream>
#include <cstdlib>
#include <cstring>
using namespace std;

const int N = 2e5, B = 4, LG = 18 - B;

class FastLCA{
    int rmq[LG][N >> B];
    int *bro, *son, *depth, *euler, *poz, *getBinBest, *bucket, *S, *D;
    int size, mask;

    inline int best(int x, int y){
        return depth[x] < depth[y] ? x : y;
    }

    inline int best(int x, int y, int z){
        return best( best(x, y), z );
    }

    inline int getBest(int x, int y){
        int buck = bucket[x >> B];
        y = 1 << (y - x);

        return euler[ x + getBinBest[ ( ( buck >> (x & mask) ) & ( y - 1 ) ) ^ y ] ];
    }

    inline int getRMQ(int x, int y){
        if (y < x) return 0;
        int L = 31 - __builtin_clz(y - x + 1);
        return best( rmq[L][x], rmq[L][y - (1 << L) + 1] );
    }

    void dfs(int x){
        poz[x] = size;
        euler[ size++ ] = x;
        for (int y = son[x] ; y ; y = bro[y]){
            depth[y] = 1 + depth[x];
            dfs(y);
            euler[ size++ ] = x;
        }
    }
public:
    void buildTree(int T[], int n){
        poz = (int*)calloc(n + 1, sizeof(int));
        depth = (int*)calloc(n + 1, sizeof(int));
        euler = (int*)calloc(2 * n, sizeof(int));
        S = bro = (int*)calloc(2 * n, sizeof(int));
        D = son = (int*)calloc(2 * n, sizeof(int));
        size = 0;

        for (int i = 2 ; i <= n ; i++){
            bro[i] = son[ T[i] ];
            son[ T[i] ] = i;
        }

        dfs(1);
        depth[0] = n;

        mask = (1 << B) - 1;
        memcpy(S, euler, size * sizeof(int));
        memcpy(D, euler, size * sizeof(int));

        S[size] = 0;
        for (int i = size - 1 ; i ; i--)
            if (i & mask)
                S[i] = best(S[i + 1], S[i]);
        for (int i = 1 ; i < size ; i++)
            if (i & mask)
                D[i] = best(D[i - 1], D[i]);

        for (int i = 0 ; i < (size >> B) ; i++)
            rmq[0][i] = D[(i << B) ^ mask];
        for (int i = 1, step = 1 ; i < LG ; i++, step <<= 1)
            for (int j = 0 ; j < (size >> B) ; j++)
                rmq[i][j] = best(rmq[i - 1][j], rmq[i - 1][j + step]);
    }

    void prepareO1(){
        getBinBest = (int*)calloc(1 << (1 << B), sizeof(int));
        bucket = (int*)calloc(1 + (N >> B), sizeof(int));

        for (int i = 2 ; i < 1 << (1 << B) ; i++){
            getBinBest[i] = 1 + getBinBest[i >> 1];
            if ( (__builtin_popcount( i & ( (1 << getBinBest[i]) - 1 ) ) << 1 ) <= getBinBest[i] )
                getBinBest[i] = 0;
        }
        for (int i = 0 ; i < size ; i++)
            if ( i & mask )
                bucket[i >> B] ^= ( depth[ euler[i] ] < depth[ euler[i - 1] ] ) << ( (i & mask) - 1);
    }

    inline int lca(int x, int y){
        x = poz[x]; y = poz[y];
        if (x > y) swap(x, y);

        if ( (x >> B) == (y >> B) ){
            int ans = 0;
            for (int i = x ; i <= y ; i++)
                ans = best(ans, euler[i]);
            return ans;
        }
        return best( S[x], getRMQ( 1 + (x >> B), (y >> B) - 1 ), D[y] );
    }

    inline int lcaO1(int x, int y){
        x = poz[x]; y = poz[y];
        if (x > y) swap(x, y);

        if ( (x >> B) == (y >> B) )
            return getBest(x, y);
        return best( S[x], getRMQ( 1 + (x >> B), (y >> B) - 1 ), D[y] );
    }
};

FastLCA tree;
int T[N], n;

int main(){
    ifstream in("lca.in");
    ofstream out("lca.out");

    int nrQ, x, y;

    in >> n >> nrQ;
    for (int i = 2 ; i <= n ; i++)
        in >> T[i];
    tree.buildTree(T, n);

    while (nrQ--){
        in >> x >> y;
        out << tree.lca(x, y) << '\n';
    }

    out.close();
    in.close();

    return 0;
}