Cod sursa(job #3331167)

Utilizator Lex._.Lex Guiman Lex._. Data 25 decembrie 2025 12:42:04
Problema Matrice 2 Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.87 kb
#include <bits/stdc++.h>
#define NMAX 301
#define QMAX 20001
#define LOG 20
using namespace std;

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

int n, q;
int matrice[NMAX][NMAX];
int ordine[NMAX*NMAX]; ///ordinea in care se iau nodurile din DSU corespunzatoare fiecarei pozitii din matrice

int dx[4]={0, -1, 0, 1};
int dy[4]={-1, 0, 1, 0}; ///vectorii de directie

int nod_asociat(int x, int y) {return (x-1)*n+y;}
int val_asociata(int nod) {return matrice[(nod-1)/n+1][(nod-1)%n+1];}

bool valid(int x, int y) {return ((x>=1 && x<=n) && (y>=1 && y<=n));}

bool cmp(int a, int b)
{return (val_asociata(a)>val_asociata(b));} ///sortam nodurile din DSU dupa valoarile din matrice

int tata[NMAX*NMAX], sz[NMAX*NMAX]; ///DSU
bitset<NMAX*NMAX> viz;

int radacina(int nod) ///calculeaza radacina unui nod din DSU
{
    while(tata[nod]!=0) nod=tata[nod];
    return nod;
}

bool aceeasi(int nod1, int nod2) ///verifica daca doua noduri fac parte din aceeasi componenta conexa din DSU
{
    int rad1=radacina(nod1), rad2=radacina(nod2);
    return (rad1==rad2);
}

void unire(int nod1, int nod2) ///uneste doua componente conexe din DSU
{
    int rad1=radacina(nod1), rad2=radacina(nod2);
    if(rad1!=rad2)
    {
        if(sz[rad1]<sz[rad2]) swap(rad1, rad2);
        sz[rad1]+=sz[rad2];
        tata[rad2]=rad1;
    }
}

void reset() ///reseteaza DSU
{
    for(int i=1; i<=n*n; i++) {tata[i]=0; sz[i]=1; viz[i]=0;}
}

struct query{int x1=0, y1=0, x2=0, y2=0, poz=0, ans=0;};
query queries[QMAX];
bool cmp_ans(query a, query b) {return a.ans<b.ans;} ///sortam query-urile dupa ans
bool cmp_poz(query a, query b) {return a.poz<b.poz;} ///sortam query-urile dupa poz

int main()
{
    in >> n >> q;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            in >> matrice[i][j];
            ordine[(i-1)*n+j]=(i-1)*n+j;
        }
    }
    sort(ordine+1, ordine+n*n+1, cmp);
    for(int j=1; j<=q; j++)
    {
        in >> queries[j].x1 >> queries[j].y1 >> queries[j].x2 >> queries[j].y2;
        queries[j].poz=j;
        queries[j].ans=0;
    }

    for(int e=LOG-1; e>=0; e--) ///cautare binara in paralel
    {
        sort(queries+1, queries+q+1, cmp_ans); ///sortam query-urile dupa raspunsul de pana acum
        reset();
        int i=1, j=1;
        while(i<=n*n) ///parcurgem nodurile (celulele din matrice)
        {
            int x=(ordine[i]-1)/n+1, y=(ordine[i]-1)%n+1; ///coordonatele din matrice corespunzatoare nodului i
            int val_matrice=matrice[x][y]; ///valoarea din matrice

            while(matrice[x][y]==val_matrice && i<=n*n) ///parcurgem toate celulele cu aceeasi valoare
            {
                viz[ordine[i]]=1; ///marcam ca fiind vizitat nodul
                for(int d=0; d<4; d++)
                {
                    int x_nou=x+dx[d], y_nou=y+dy[d]; ///coordonatele din matrice corespunzatoare nodului vecin
                    if(valid(x_nou, y_nou))
                    {
                        if(viz[nod_asociat(x_nou, y_nou)]) unire(ordine[i], nod_asociat(x_nou, y_nou)); ///daca nodul vecin a fost vizitat pana acum, il adaugam la aceeasi componenta conexa ca nodul curent
                    }
                }
                i++;
                x=(ordine[i]-1)/n+1, y=(ordine[i]-1)%n+1;
            }
            while(j<=q && queries[j].ans+(1<<e)<=n*n && val_asociata(ordine[queries[j].ans+(1<<e)])>=val_matrice) ///raspundem la query-uri
            {
                if(aceeasi(nod_asociat(queries[j].x1, queries[j].y1), nod_asociat(queries[j].x2, queries[j].y2))==0) queries[j].ans+=(1<<e);
                j++;
            }
        }
    }
    sort(queries+1, queries+q+1, cmp_poz); ///sortam query-urile dupa pozitie
    for(int j=1; j<=q; j++)
    {
        out << val_asociata(ordine[queries[j].ans+1]) << "\n";
    }

    return 0;
}