Cod sursa(job #1190131)

Utilizator mihai995mihai995 mihai995 Data 24 mai 2014 16:14:58
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.28 kb
#include <fstream>
#include <cstring>
#include <cmath>
using namespace std;

const int N = 1 + 1e5, BB = 16, LG = 14;
const int Size = BB + 2 * N / BB;

class OptimalLCA{
    int son[N], bro[N], depth[N];
    int euler[2 * N + 2 * BB], position[N];
    int bMask[1 << BB], bucket[Size], n;
    int rmq[LG][Size];

    void dfs(int x, int T){
        depth[x] = 1 + depth[T];
        euler[ ++euler[0] ] = x;
        position[x] = euler[0];

        for (int i = son[x] ; i ; i = bro[i]){
            dfs(i, x);
            euler[ ++euler[0] ] = x;
        }
    }

    void computeMask(int p, int mask, int val, int best, int bestVal){
        bMask[ mask ^ (1 << p) ] = best;

        if (p + 1 != BB){
            computeMask(p + 1, mask, val - 1, best, bestVal);

            ++val;
            if (bestVal < val)
                computeMask(p + 1, mask ^ (1 << p), val, p + 1, val);
            else
                computeMask(p + 1, mask ^ (1 << p), val, best, bestVal);
        }
    }

    int getBucket(int st, int dr){
        int ans = 0;
        for (int i = st + 1, sw = 1 ; i < dr ; i++, sw <<= 1)
            if ( depth[ euler[i] ] < depth[ euler[i - 1] ] )
                ans ^= sw;
        return ans;
    }

    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 maskQuery(int x, int y){
        int L = 1 << (y - x), mask = (bucket[x >> 4] >> (x & 15) ) & (L - 1);
        return euler[ x + bMask[ mask ^ L ] ];
    }

    inline int rmqQuery(int x, int y){
        if (y < x) return 0;
        int L = 31 - __builtin_clz(y - x);
        return best( rmq[L][x], rmq[L][ y - (1 << L) + 1 ] );
    }
public:
    void build(int T[], int n){
        memset(son, 0, sizeof(son));
        memset(bro, 0, sizeof(bro));
        this -> n = n;
        euler[0] = 0;

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

        dfs(1, 0);
        computeMask(0, 0, 0, 0, 0);

        int size = 1 + (n >> 3);
        for (int i = 0 ; i <= size ; i++){
            bucket[i] = getBucket(i << 4, (i + 1) << 4);
            rmq[0][i] = euler[ (i << 4) + bMask[ bucket[i] ^ 32768 ] ];
        }

        depth[0] = n;
        for (int i = 1, step = 1 ; i < LG ; i++, step <<= 1)
            for (int j = 1 ; j + step <= size ; j++)
                rmq[i][j] = best(rmq[i - 1][j], rmq[i - 1][j + step]);
    }

    int lca(int x, int y){
        x = position[x];
        y = position[y];
        if (y < x) swap(x, y);

        int pX = x >> 4, pY = y >> 4;

        if (pX == pY)
            return maskQuery(x, y);
        return best( maskQuery(x, ( (pX + 1) << 4) - 1), rmqQuery(pX + 1, pY - 1), maskQuery( pY << 4, y ) );
    }
};

OptimalLCA tree;
int T[N];

int main(){
    int nrQ, n, x, y;
    ifstream in("lca.in");

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

    tree.build(T, n);

    ofstream out("lca.out");

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

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

    return 0;
}