Cod sursa(job #2301355)

Utilizator popescu.octavianPopescu Octavian popescu.octavian Data 12 decembrie 2018 21:00:48
Problema Range minimum query Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.93 kb
#include <bits/stdc++.h>

using namespace std;

unsigned int N, M, block_size, block_nr, root;
vector<int> euler_representation, level, first_appearance, log_2, block_mask, v, parent;
vector<vector<int>> tree, b;
vector<vector<vector<int>>> blocks;
vector<pair<int, int>> queries;
stack<int> s;

void ReadInput(istream &f) {
    f >> N >> M;

    for(int i = 0; i < N; i++) {
        int x;
        f >> x;
        v.push_back(x);
    }
//    for(int i = 0; i < M; i++) {
//        int a, b;
//        f >> a >> b;
//        queries.push_back(make_pair(a - 1, b - 1));
//    }
}
void BuildCartesianTree() {
    for (int i = 0; i < N; i++) {
        int last = -1;
        while (!s.empty() && v[s.top()] >= v[i]) {
            last = s.top();
            s.pop();
        }
        if (!s.empty()) {
            parent[i] = s.top();
        }
        if (last >= 0) {
            parent[last] = i;
        }
        s.push(i);
    }
}
void DFS(int node, int source, int crtLevel) {
    euler_representation.push_back(node);
    first_appearance[node] = euler_representation.size() - 1;
    level[node] = crtLevel;


    for(int x : tree[node]) {
        if (x != source) {
            DFS(x, node, crtLevel + 1);

            euler_representation.push_back(node);
        }
    }

}
int min_levelwise(int x, int y) {
    return level[euler_representation[x]] < level[euler_representation[y]] ? x : y;
}
void Precompute() {
    int nr = euler_representation.size();
    log_2.push_back(-1);
    for(int i = 1; i <= nr; i++) {
        log_2.push_back(log_2[i / 2] + 1);
    }

    block_size = max(1, log_2[nr] / 2);
    block_nr = (nr + block_size - 1) / block_size;

    b.assign(block_nr, vector<int>(log_2[block_nr] + 1));
    for(int i = 0, j = 0, block = 0; i < nr; i++, j++) {
        if(j == block_size) {
            block++;
            j = 0;
        }
        if(j == 0 || min_levelwise(b[block][0], i) == i) {
            b[block][0] = i;
        }
    }
    for(int j = 1; j <= log_2[block_nr]; j++) {
        for(int i = 0; i < block_nr; i++) {
            int p = i + (1 << (j - 1));
            if(p >= block_nr) {
                b[i][j] = b[i][j - 1];
            }
            else {
                b[i][j] = min_levelwise(b[i][j - 1], b[p][j - 1]);
            }
        }
    }

    block_mask.assign(block_nr, 0);
    for(int i = 0, j = 0, block = 0; i  < nr; i++, j++) {
        if(j == block_size) {
            j = 0;
            block++;
        }
        if(j > 0 && (i >= nr || min_levelwise(i - 1, i) == i - 1)) {
            block_mask[block] += 1 << (j - 1);
        }
    }

    unsigned int total = 1 << (block_size - 1);
    blocks.resize(total);
    for(int block = 0; block < block_nr; block++) {
        int mask = block_mask[block];
        if(blocks[mask].empty()) {
            blocks[mask].assign(block_size, vector<int>(block_size));
            for (int l = 0; l < block_size; l++) {
                blocks[mask][l][l] = l;
                for (int r = l + 1; r < block_size; r++) {
                    blocks[mask][l][r] = blocks[mask][l][r - 1];
                    if (block * block_size + r < nr)
                        blocks[mask][l][r] = min_levelwise(block * block_size + blocks[mask][l][r],
                                block * block_size + r) - block * block_size;
                }
            }
        }
    }
}
int LCA_block(int block, int l, int r) {
    return blocks[block_mask[block]][l][r] + block * block_size;
}
int LCA(int x, int y) {
    int l = first_appearance[x];
    int r = first_appearance[y];

    if(l > r) {
        int aux = l;
        l = r;
        r = aux;
    }

    int block_l = l / block_size;
    int block_r = r / block_size;

    if(block_l == block_r) {
        return euler_representation[LCA_block(block_l, l % block_size, r % block_size)];
    }

    int sol1 = LCA_block(block_l, l % block_size, block_size - 1);
    int sol2 = LCA_block(block_r, 0, r % block_size);
    int solution = min_levelwise(sol1, sol2);

    if(block_l + 1 < block_r) {
        int logarithm = log_2[block_r - block_l - 1];
        int sol3 = b[block_l + 1][logarithm];
        int sol4 = b[block_r - (1 << logarithm)][logarithm];
        solution = min_levelwise(solution, min_levelwise(sol3, sol4));
    }
    return euler_representation[solution];
}
void PrintOutput(ostream &g) {
    int a, b;
    for(int i = 0; i < M; i++){
        f >> a >> b;
        g << v[LCA(a - 1, b - 1)] << '\n';
    }
}
void InitializeTree() {
    tree.resize(N);
    for(int i = 0; i < parent.size(); i++) {
        if(parent[i] == -1) {
            root = i;
        }
        else {
            tree[parent[i]].push_back(i);
        }
    }
    first_appearance.resize(N);
    level.resize(N);
}
int main() {
    ifstream f;
    f.open("rmq.in");

    ofstream g;
    g.open("rmq.out");

    ReadInput(f);

    parent.assign(N, -1);
    BuildCartesianTree();

    InitializeTree();

    DFS(root, -1, 0);

    Precompute();

    PrintOutput(g);

    f.close();
    g.close();
    return 0;
}