Cod sursa(job #1189962)

Utilizator mihai995mihai995 mihai995 Data 24 mai 2014 00:56:09
Problema Lowest Common Ancestor Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 3.09 kb
#include <fstream>
#include <vector>
using namespace std;

const int N = 1 + 1e5, inf = 0x3f3f3f3f;
const int LG = 17, Bucket = 8;
const int Size = 1 + 2 * N / Bucket;

int rmq[LG][Size], bucketMask[Size], bucketQuery[1 << (Bucket + 1)];
int T[N], depth[N], euler[2 * N + 2 * Bucket], start[N], timp, n;
vector<int> tree[N];

void dfs(int x){
    start[x] = timp;
    euler[ timp++ ] = x;

    for (auto it = tree[x].begin() ; it != tree[x].end() ; it++)
        if (depth[*it] == 0){
            depth[*it] = 1 + depth[x];
            dfs(*it);
            euler[ timp++ ] = x;
        }
}

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( x, best(y, z) );
}

inline int rmqQuery(int st, int dr){
    if (dr < st)
        return 0;

    int L = 31 - __builtin_clz(dr - st + 1);
    return best( rmq[L][st], rmq[L][dr - (1 << L) + 1] );
}

inline int midQuery(int x, int y){
    int mask = ( bucketMask[x / Bucket] >> (x % Bucket) ) & ( ( 1 << (y - x + 1) ) - 1 );
    mask ^= 1 << (y - x + 1);
    return euler[ x + bucketQuery[mask] ];
}

inline int leftQuery(int x){
    return midQuery( x / Bucket * Bucket, x );
}

inline int rightQuery(int x){
    return midQuery(x, (x / Bucket + 1) * Bucket - 1 );
}
int lca(int x, int y){
    x = start[x];
    y = start[y];

    if (x > y) swap(x, y);

    if (x / Bucket == y / Bucket)
        return midQuery(x, y);
    return best( rightQuery(x), rmqQuery(x / Bucket + 1, y / Bucket - 1), leftQuery(y) );
}

inline int getDepth(int mask, int poz){
    poz++;
    return poz - 2 * __builtin_popcount( mask & ( (1 << poz) - 1 ) );
}

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

void compute(){
    depth[0] = inf;
    depth[1] = 1;
    dfs(1);

    for (int i = 4 ; i < 1 << (Bucket + 1) ; i++){
        int p = 30 - __builtin_clz(i), mask = i ^ ( 1 << (p + 1) );
        if ( getDepth(mask, p) < getDepth(mask, bucketQuery[mask | (1 << p)]) )
            bucketQuery[i] = p;
        else
            bucketQuery[i] = bucketQuery[mask | (1 << p)];
    }

    int size = 1 + 2 * n / Bucket;
    for (int i = 0 ; i <= size ; i++){
        bucketMask[i] = getMask( i * Bucket, (i + 1) * Bucket );
        rmq[0][i] = euler[ i * Bucket + bucketQuery[ bucketMask[i] ^ (1 << (Bucket + 1) ) ] ];
    }
    for (int i = 1, step = 1 ; i < LG ; i++, step <<= 1)
        for (int j = 0 ; j + step <= size ; j++)
            rmq[i][j] = best( rmq[i - 1][j], rmq[i - 1][j + step] );
}

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

    in >> n >> nrQ;
    for (int i = 2 ; i <= n ; i++){
        in >> T[i];
        tree[ T[i] ].push_back(i);
    }

    compute();

    ofstream out("lca.out");

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

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

    return 0;
}