Pagini recente » Cod sursa (job #2145959) | Cod sursa (job #2644781) | Cod sursa (job #1078912) | Monitorul de evaluare | Cod sursa (job #3331167)
#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;
}