Cod sursa(job #1234485)

Utilizator gabrielinelusGabriel-Robert Inelus gabrielinelus Data 27 septembrie 2014 14:33:21
Problema Matrice 2 Scor 100
Compilator cpp Status done
Runda Teme Pregatire ACM Unibuc 2013 Marime 5.13 kb
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
#include <bitset>
#include <cmath>

#define Nmax 301*301
#define INF 0x3f3f3f3f

using namespace std;

priority_queue<pair<int,pair<int,int> >,
        vector<pair<int,pair<int,int> > > > Heap;

int N,Q,m[305][305],daddy[Nmax],nrl;
vector<int> G[Nmax];
vector<int> lantz[Nmax];/// lanturile
vector<int> range[Nmax]; /// pentru aint
bitset<Nmax>used;
int valori[Nmax]; /// valoarea nodului i
int heavy[Nmax]; /// greutatea nodului i
int height[Nmax]; /// adancimea nodului i
int care[Nmax]; /// in care lantz se afla i
int tata_lantz[Nmax]; /// nodul de care se leaga lantzul i
int pozitie_nod[Nmax]; /// pozitia nodului i in lantzul sau

int code(int x,int y)
{
    return (x-1)*N+y;
}
int INmatrix(int x,int y)
{
    if( 1 <= x && x <= N &&
        1 <= y && y <= N) return 1;
    return 0;
}
int whos_ur_daddy(int k)
{
    if(daddy[k] != k)
        daddy[k] = whos_ur_daddy(daddy[k]);
    return daddy[k];
}
int couple(int a,int b)
{
    daddy[daddy[a]] = daddy[b];
}
class cmp{
public:
    bool operator()(const int x,const int y) const
    {
        return heavy[x] > heavy[y];
    }
};

void read()
{
    scanf("%d%d",&N,&Q);
    for(int i = 1; i <= N; ++i)
        for(int j = 1; j <= N; ++j)
            scanf("%d",&m[i][j]);
    for(int i = 1; i <= N; ++i)
    {
        for(int j = 1; j <= N; ++j)
        {
            if(INmatrix(i+1,j))
                Heap.push(make_pair(min(m[i][j],m[i+1][j]),
                       make_pair(code(i,j),code(i+1,j))));
            if(INmatrix(i,j+1))
                Heap.push(make_pair(min(m[i][j],m[i][j+1]),
                       make_pair(code(i,j),code(i,j+1))));
        }
    }
}

void kruskal()
{
    int a,b,c;
    for(int i = 1; i <= N*N; ++i) daddy[i] = i;
    while(!Heap.empty())
    {
        c = Heap.top().first;
        a = Heap.top().second.first;
        b = Heap.top().second.second;
        Heap.pop();
        if(whos_ur_daddy(a) != whos_ur_daddy(b))
        {
            couple(a,b);
            G[a].push_back(b);
            G[b].push_back(a);
        }
    }
}

void DFSG(int k,int niv)
{
    used[k] = 1;
    height[k] = niv;
    for(vector<int>::iterator it = G[k].begin(); it != G[k].end(); ++it)
        if(!used[*it])
        {
            DFSG(*it,niv+1);
            heavy[k] += 1 + heavy[*it];
        }
}

void descomp(int k)
{
    care[k] = nrl;
    lantz[nrl].push_back(k);
    pozitie_nod[k] = lantz[nrl].size() - 1;
    used[k] = 1;
    for(vector<int>::iterator it = G[k].begin(); it != G[k].end(); ++it)
        if(!used[*it])
        {
            if(lantz[nrl].size() == 1)
                tata_lantz[nrl] = k;
            descomp(*it);
        }
    if(G[k].size() == 1 && k != 1){
        ++nrl; /// frunzaaa :D
        lantz[nrl].push_back(0);
    }
}

void decomposition()
{
    DFSG(1,0);
    for(int i = 1; i <= N*N; ++i)
        sort(G[i].begin(),G[i].end(),cmp());
    ++nrl;used = 0;
    lantz[1].push_back(0);
    descomp(1); -- nrl;
    for(int i = 1; i <= nrl; ++i)
        for(int j = 0; j <= (1<<((int)log2(lantz[i].size())+ 1)) + 1 ; ++j)
            range[i].push_back(0);
    for(int i = 1; i <= N; ++i)
        for(int j = 1; j <= N; ++j)
            valori[(i-1)*N+j] = m[i][j];
}
int line,A,B,answer;

class SegmentTree{
public:
    void Build(int li,int lf,int pz)
    {
        if(li == lf)
        {
            range[line][pz] = valori[lantz[line][li]];
            return;
        }
        int m = li + ((lf-li)>>1);
        Build(li,m,pz<<1);
        Build(m+1,lf,(pz<<1)|1);
        range[line][pz] = min(range[line][pz<<1],range[line][(pz<<1)|1]);
    }
    void Querry(int li,int lf,int pz)
    {
        if(A <= li && lf <= B)
        {
            answer = min(answer,range[line][pz]);
            return;
        }
        int m = li+((lf-li)>>1);
        if(A <= m) Querry(li,m,pz<<1);
        if(m < B) Querry(m+1,lf,(pz<<1)|1);
    }
    void Make()
    {
        for(int i = 1; i <= nrl; ++i)
        {
            line = i;
            Build(1,lantz[i].size()-1,1);
        }
    }

}Aint;

void solve()
{
    int x1,y1,x2,y2,x,y;
    for(int i = 1; i <= Q; ++i)
    {
        answer = INF;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        x = code(x1,y1);
        y = code(x2,y2);
        while(care[x] != care[y])
        {
            if(height[tata_lantz[care[x]]] < height[tata_lantz[care[y]]]) swap(x,y);
            if(care[x] == 1) swap(x,y);
            line = care[x];
            A = 1;
            B = pozitie_nod[x];
            Aint.Querry(1,lantz[line].size()-1,1);
            x = tata_lantz[care[x]];
        }
        A = pozitie_nod[x];
        B = pozitie_nod[y];
        line = care[x];
        if(A > B)swap(A,B);
        Aint.Querry(1,lantz[line].size()-1,1);
        printf("%d\n",answer);
    }
}

int main()
{
    freopen("matrice2.in","r",stdin);
    freopen("matrice2.out","w",stdout);

    read();
    kruskal();
    decomposition();
    Aint.Make();
    solve();

    return 0;
}