Cod sursa(job #829708)

Utilizator vendettaSalajan Razvan vendetta Data 5 decembrie 2012 19:08:19
Problema Matrice 2 Scor 55
Compilator cpp Status done
Runda Arhiva de probleme Marime 7.81 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <set>
#include <queue>
#include <deque>

using namespace std;

ifstream f("matrice2.in");
ofstream g("matrice2.out");

#define nmax (301*301)
#define ll long long
#define Ceva 17
#define inf (1<<29)

const int dx[] = {0, -1, 0, 1};
const int dy[] = {-1, 0, 1, 0};
const int h = 200;

int n, m, P[nmax],  t[nmax], secv[nmax*2], nivel[nmax];//, Min[Ceva][nmax*2], Nod[Ceva][nmax*2];
bool viz[nmax];
int rezMin[Ceva][nmax], cine[Ceva][nmax];
//int aint[nmax*2*4];
int t2[nmax];
vector< pair<int,int> > gf[nmax];
int cnt;
pair< pair<int,int>, int> v[nmax*2];
int a[3][301];

void citeste(){

	f >> n >> m;
	int k = 0;
	for(int i=1; i<=n; ++i){
        int linie = 0;
        if (i & 1) linie = 1;
        for(int j=1; j<=n; ++j){
            ++k;
            f >> a[linie][j];
            //f >> a[i][j];
            //fac muchiile
            if (k - n > 0) v[++cnt] = make_pair( make_pair(k, k-n), min(a[linie][j], a[1-linie][j]) );
            if (j - 1 > 0) v[++cnt] = make_pair( make_pair(k, k-1), min(a[linie][j], a[linie][j-1]) );
        }
	}

}


void transforma(int x1, int y1, int x2, int y2, int &i, int &j){

    i = (n * x1) - (n - y1);
    j = (n * x2) - (n - y2);

}

inline bool check(int x, int y){

    if (x > 0 && y > 0 && x <= n && y <= n) return 1;
    return 0;

}

void fa_graf(){

    for(int i=1; i<=n; ++i){
        for(int j=1; j<=n; ++j){
            for(int k=0; k<4; ++k){
                int new_i = i + dx[k];
                int new_j = j + dy[k];
                if (check(new_i, new_j) ){
                    int x = 0; int y = 0;
                    transforma( i, j, new_i, new_j, x, y );
                    v[++cnt] = make_pair( make_pair(x, y), min(a[i][j], a[new_i][new_j]) );
                }
            }
        }
    }

}

bool cmp( pair< pair<int,int>, int> a, pair< pair<int,int>, int > b){

    return (a.second > b.second);

}

int afla(int x){

    int cpy = x;
    for(; t[x] != 0; x=t[x]);
    while(cpy != x){
        int unde = t[cpy];
        t[cpy] = x;
        cpy = unde;
    }
    return x;

}

void uneste(int x, int y){

    t[x] = y;

}

void fa_apm(){

    //fac apm de cost maxim
    sort(v+1, v+cnt+1, cmp);

    for(int i=1; i<=cnt; ++i){
        int x = v[i].first.first;
        int y = v[i].first.second;
        int c = v[i].second;
        int radx = afla(x); int rady = afla(y);
        if (radx == rady) continue;// sunt in aceeasi componenta
        uneste(radx, rady);
        //cout << x << " " << y << " " << c << "\n";
        gf[x].push_back( make_pair(y, c) );
        gf[y].push_back( make_pair(x, c) );
    }

}


void init(int tata, int nod, int cost){

    rezMin[0][nod] = cost;
    cine[0][nod] = tata;// cien ii al 2 ^ 0 tata pt nod

}

void dfs(int nod, int n2, int niv){

    viz[nod] = 1;
    //secv[++secv[0]] = nod;
    //P[nod] = secv[0];
    t2[nod] = n2;
    if (niv % h == 0) n2 = nod;
    nivel[nod] = niv;

    for(int i=0; i<gf[nod].size(); ++i){
        int vc = gf[nod][i].first;
        if (viz[vc] == 0){
            init(nod, vc, gf[nod][i].second);//initializez rmq-ul pt muchia minima
            t[vc] = nod;
            dfs(vc, n2, niv+1);
            //secv[ ++secv[0] ] = nod;
            //U[nod] = secv[0];
        }
    }
    //U[nod] = secv[0];

}
/*
void fa_lca(){

    //elementul cu nivelul minim din intervalul P[x], U[x]
    for(int i=1; i<=secv[0]; ++i){
        Min[0][i] = nivel[ secv[i] ];//nivelul pe care se afla
        Nod[0][i] = secv[i];// nodul care se afla
    }

    for(int i=1; i<17; ++i){
        int put = (1<<i);
        for(int j=1; j<=secv[0]; ++j){
            int Y = j + put - 1;// el tine pe intervalul [j, Y];
            int X = Y - ( 1<<(i-1) ) + 1;
            Min[i][j] = Min[i-1][j];
            Nod[i][j] = Nod[i-1][j];
            if (Min[i][j] > Min[i-1][X]){
                Min[i][j] = Min[i-1][X];
                Nod[i][j] = Nod[i-1][X];
            }
        }
    }
    //cam atat

}
*/
void fa_muchie(){

    //acum aflu muchia minima
    for(int i=1; i<17; ++i){
        int put = (1<<i);
        for(int j=1; j<=n*n; ++j){
            int new_x = cine[i-1][j];
            cine[i][j] = cine[i-1][new_x];
            rezMin[i][j] = min(rezMin[i-1][j], rezMin[i-1][new_x]);
        }
    }

}


void afla_lca(int &Lca, int x, int y){

    while(t2[x] != t2[y]){
        if (nivel[x] > nivel[y]){
            x = t2[x];
        }else y = t2[y];
    }

    while(x != y){
        if (nivel[x]>nivel[y]){
            x = t[x];
        }else y = t[y];
    }

    Lca = x;


/*
    int p1 = P[x];
    int p2 = P[y];
    if (p1 > p2) swap(p1, p2);//daca apara dupa p2
    //acum trebuie sa aflu minimul de pe intervalul p1, p2;
    int lung = p2 - p1 + 1;
    int rez = inf;
    for(int i=17; i>=0; --i){
        if ( (lung & (1<<i) ) != 0 ){
            if (rez > Min[i][p1]){
                rez = Min[i][p1];
                Lca = Nod[i][p1];
            }
            p1 = p1 + (1<<i) -1;
        }

    }
*/

}

void afla_cost(int nod, int lca, int &cost){

    int k = nivel[nod] - nivel[lca];// al cate-lea tata e lca
    //cout << " K: " << k << " " << nod << " " << lca << "\n";
    for(int i=17; i>=0; --i){
        if ( ( k & (1<<i) ) != 0 ){
            cost = min(cost, rezMin[i][nod]);
            nod = cine[i][nod];
        }
    }

}
/*
void udpate(int nod, int st, int dr, int poz, int val){

    if (st == dr){
        aint[nod] = poz;
        return;
    }else{
        int mij =(st + dr) / 2;
        if (poz <= mij) udpate(nod*2, st, mij, poz, val);
        if (poz > mij) udpate(nod*2+1, mij+1, dr, poz, val);
        aint[nod] = aint[nod*2];
        if ( nivel[ secv[aint[nod] ] ] > nivel[ secv[ aint[nod*2+1] ] ] ){
            aint[nod] = aint[nod*2+1];
        }
    }

}

void query(int nod, int st, int dr, int a, int b, int &nv, int &lca){

    if (a <= st && dr <= b){
        if ( nv > nivel[ secv[ aint[nod] ] ] ){
            nv = nivel[ secv[aint[nod]] ];
            lca = secv[aint[nod]];
        }
        return;
    }else{
        int mij = (st + dr) / 2;
        if (a <= mij) query(nod*2, st, mij, a, b, nv, lca);
        if (b > mij) query(nod*2+1, mij+1, dr, a, b, nv, lca);
    }

}
*/
void rezolva(){

    //fa_graf();

    fa_apm();

    for(int i=0; i<nmax; ++i) t[i] = 0;//numai am nevoie de ei; o sa am nevoie la muchia minima

    //initializez pt muchia minima
    for(int i=0; i<17; ++i){
        for(int j=0; j<nmax; ++j) rezMin[i][j] = inf;
    }
    dfs(1,0,1);
    /*
    for(int i=1; i<=secv[0]; ++i){
        udpate(1, 1, secv[0], i, nivel[secv[i]]);
    }
    */
    /*
    for(int i=1; i<=n*n; ++i){
        cout << nivel[i] << " ";
    }
    cout << "\n";
    */

    //fa_lca();
    //acum stiu lca;
    //acum aflu muchia minima de pe drumul  x-lca, y-lca
    fa_muchie();

    //acum raspund la query-uri

    for(int i=1; i<=m; ++i){
        int x1, y1, x2, y2;
        f >> x1 >> y1 >> x2 >> y2;
        int X = 0; int Y = 0;
        transforma(x1, y1, x2, y2, X, Y);
        //aflu lca-ul dintre X si Y;
        int Lca = 0;
        int x = P[X];
        int y = P[Y];
        if (x > y) swap(x,y);
        //int nv = inf;
        //query(1, 1, secv[0], x, y, nv, Lca);
        afla_lca(Lca, X, Y);
        int cost_min = inf;
        afla_cost(X, Lca, cost_min);
        afla_cost(Y, Lca, cost_min);
        //cout << X << " " << Y << " " << Lca << " " << nivel[X] << " " << nivel[Lca] << " " << nivel[Y]<< "\n";
        cout << cost_min << "\n";
        g << cost_min << "\n";
    }

}

int main(){

    citeste();
    rezolva();

    f.close();
    g.close();

    return 0;

}