Cod sursa(job #2068677)

Utilizator MaligMamaliga cu smantana Malig Data 18 noiembrie 2017 10:22:54
Problema Paduri de multimi disjuncte Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 5.09 kb
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <unordered_map>

#if 1
#define pv(x) cout<<#x<<" = "<<x<<"; ";cout.flush()
#define pn cout<<endl
#else
#define pv(x)
#define pn
#endif

using namespace std;
ifstream in("pirati.in");
ofstream out("pirati.out");

#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
const int NMax = 1e3 + 50;
const int sMax = 25e4 + 5;
typedef pair<int,int> point;

int N,M,Q,nrComp,nrEuler;
int code[NMax][NMax];
int depth[sMax],dad[sMax],euler[sMax],pos[sMax],lg[sMax],rmq[sMax][20],disjointDad[sMax],nr[sMax];
vector<int> v[sMax];
map<pair<int,int>,bool> adj;
const int dx[8] = {-1,-1,-1,0,0,+1,+1,+1},dy[8] = {-1,0,+1,-1,+1,-1,0,+1};

void lee(int,int);
void getEdges();
void dfs(int);
int findRoot(int);
void unite(int,int);

int main() {
    in>>N>>M>>Q;
    for (int i=1;i <= N;++i) {
        for (int j=1;j <= M;++j) {
            int idx = (i-1) * M + j;
            disjointDad[idx] = idx;
            nr[idx] = 1;

            char c;
            in>>c;

            code[i][j] = c - '0';
        }
    }

    /*
    for (int i=1;i <= N;++i) {
        for (int j=1;j <= M;++j) {
            cout<<code[i][j]<<' ';
        }
        cout<<'\n';
    }
    cout<<'\n';
    //*/

    nrComp = 10;
    for (int i=1;i <= N;++i) {
        for (int j=1;j <= M;++j) {

            if (code[i][j] <= 1) {
                ++nrComp;
                lee(i,j);
            }
        }
    }

    for (int i=0;i <= nrComp;++i) {
        depth[i] = dad[i] = 0;
    }

    depth[11] = 1;
    dfs(11);

    lg[1] = 0;
    rmq[1][0] = euler[1];
    for (int i=2;i <= nrEuler;++i) {
        lg[i] = lg[i/2] + 1;
        rmq[i][0] = euler[i];
    }

    for (int p=1;(1<<p) <= nrEuler;++p) {
        for (int i=1;i + (1<<p) - 1 <= nrEuler;++i) {
            int pos1 = rmq[i][p-1],
                pos2 = rmq[i+(1<<(p-1))][p-1];

            if (depth[pos1] < depth[pos2]) {
                rmq[i][p] = pos1;
            }
            else {
                rmq[i][p] = pos2;
            }
        }
    }

    /*
    for (int i=1;i <= N;++i) {
        for (int j=1;j <= M;++j) {
            cout<<code[i][j]<<' ';
        }
        cout<<'\n';
    }
    cout<<'\n';
    //*/

    /*
    for (int i=11;i <= nrComp;++i) {
        for (int node : v[i]) {
            cout<<node<<' ';
        }
        cout<<'\n';
    }
    cout<<'\n';
    //*/

    /*
    for (int i=11;i <= nrComp;++i) {
        pv(i);pv(depth[i]);pv(dad[i]);pn;
    }
    cout<<'\n';
    //*/


    while (Q--) {
        int x1,y1,x2,y2;
        in>>x1>>y1>>x2>>y2;

        int node1 = code[x1][y1], node2 = code[x2][y2];
        int pos1 = pos[node1], pos2 = pos[node2];
        if (pos1 > pos2) {
            swap(pos1,pos2);
        }

        int pw = lg[pos2 - pos1 + 1], lca;
        pos1 = rmq[pos1][pw], pos2 = rmq[pos2 - (1<<pw) + 1][pw];
        if (depth[pos1] < depth[pos2]) {
            lca = pos1;
        }
        else {
            lca = pos2;
        }

        out<<(depth[node1] - depth[lca] + depth[node2] - depth[lca])/2<<'\n';
    }

    return 0;
}

void lee(int x,int y) {
    queue<point> Q;
    int curr = code[x][y];

    Q.push(point(x,y));
    code[x][y] = nrComp;
    while (Q.size()) {
        point p = Q.front();
        Q.pop();

        //pv(p.first);pv(p.second);pn;

        for (int k=0;k < 8;++k) {
            int nx = p.first + dx[k],
                ny = p.second + dy[k];

            if (nx < 1 || nx > N || ny < 1 || ny > M) {
                continue;
            }

            point neighbour(nx,ny);
            if (curr == code[nx][ny]) {
                code[nx][ny] = nrComp;
                Q.push(neighbour);
            }
            else if (code[nx][ny] > 1 && code[nx][ny] != nrComp) {
                int comp1 = nrComp, comp2 = code[nx][ny];

                if (findRoot(comp1) == findRoot(comp2)) {
                    continue;
                }

                unite(comp1,comp2);
                v[comp1].pb(comp2);
                v[comp2].pb(comp1);
            }
        }
    }
}

void dfs(int node) {
    euler[++nrEuler] = node;
    pos[node] = nrEuler;

    for (int nxt : v[node]) {
        if (depth[nxt]) {
            continue;
        }

        dad[nxt] = node;
        depth[nxt] = depth[node] + 1;
        dfs(nxt);
        euler[++nrEuler] = node;
    }
}

int findRoot(int node) {
    if (disjointDad[node] == node) {
        return node;
    }

    int root = findRoot(disjointDad[node]);
    disjointDad[node] = root;
    return root;
}

void unite(int x,int y) {
    int rootX = findRoot(x),
        rootY = findRoot(y);

    if (nr[rootX] > nr[rootY]) {

        nr[rootX] += nr[rootY];
        nr[rootY] = 0;
        disjointDad[rootY] = rootX;
    }
    else {

        nr[rootY] += nr[rootX];
        nr[rootX] = 0;
        disjointDad[rootX] = rootY;
    }
}