Cod sursa(job #798718)

Utilizator rvnzphrvnzph rvnzph Data 17 octombrie 2012 00:05:21
Problema Matrice 2 Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.45 kb
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>

#define NLen 0x200
#define QLen 0x8000
#define NumLen 0x100000

using namespace std;

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

int Mat[NLen][NLen];

char frq[NumLen];
int use[NumLen];
int G[NLen*NLen];
int aux[QLen];
int Sol[QLen];

int N;
int Q;
int last;

struct Point
{
	int sx,sy,fx,fy;
}P[QLen];

struct Position
{
	int value,idx;
}v[NLen*NLen],h[QLen];

inline bool Comp_v(const Position &a,const Position &b)
{
	return a.value<b.value;
}

inline bool Comp_h(const Position &a,const Position &b)
{
	return a.value>b.value;
}

inline int Convert(int a,int b)
{
	return (a-1)*N+b;
}

inline int root(int nod)
{
	if(G[nod]!=nod) G[nod]=root(G[nod]);
	return G[nod];
}

inline void unite(int x,int y)
{
	G[root(x)]=root(y);
}

inline void grow(int H)
{
	//fiecare element care nu a fost deja pus in graf il unesc cu padurile din jur
	int i;
	
	for(i=last;i>0&&v[i].value>=H;--i)
	{
		int x=v[i].idx/N;
		int y=v[i].idx%N;

		if(y==0) y=N;
		else ++x;

		for(int j=0;j<4;++j)
			if(0<x+dx[j]&&x+dx[j]<=N&&
				0<y+dy[j]&&y+dy[j]<=N&&
				Mat[x+dx[j]][y+dy[j]]>=H)
			{
				unite(v[i].idx,Convert(x+dx[j],y+dy[j]));
			}
	}

	last=i;
}

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

	cin>>N>>Q;
	
	for(int i=1;i<=N;++i)
		for(int j=1;j<=N;++j)
			cin>>Mat[i][j];

	for(int i=1;i<=Q;++i)
		cin>>P[i].sx>>P[i].sy>>P[i].fx>>P[i].fy;

	//folosesc un vector de frecventa pe care il restrans (elimin 0-urile)

	for(int i=1;i<=N;++i)
		for(int j=1;j<=N;++j)
			frq[Mat[i][j]]=1;

	int M=0;
	for(int i=1;i<NumLen;++i)
		if(frq[i]) use[++M]=i;

	//transform matricea in vector
	//sortez elementele vectorului

	int L=0;
	for(int i=1;i<=N;++i)
		for(int j=1;j<=N;++j)
		{
			v[++L].value=Mat[i][j];
			v[L].idx=L;
		}

	sort(v+1,v+L+1,Comp_v);

	//fac cautarile binare smechere in paralel
	//construiesc graful pe parcurs, caut binar query-urile care au un h mai mare
	//h = pozitia inaltimii in use
	//use = valuarea efectiva a inaltimii

	memset(h,0,sizeof(h));
	for(int i=1;i<=Q;++i) h[i].idx=i;

	int step;
	for(step=1;step<M;step*=2);

	for(;step;step/=2)
	{
		//resetez graful G
		for(int i=1;i<=L;++i) G[i]=i;

		//last e pozitia primului element pe care il pun in padure
		//in functia grow
		last=L;

		//sortez h (inaltimile minime care trebuie sa fie pe drum) in ordine descrescatoare,
		//ca sa pot sa extind graful

		sort(h+1,h+Q+1,Comp_h);

		//folosesc un vector auxiliar deoarece am nevoie de h-urile vechi pentru a imi da seama cand extind G
		for(int i=1;i<=Q;++i) aux[i]=h[i].value;

		for(int i=1;i<=Q;++i)
			if(h[i].value+step<=M) //conditie pentru BS
			{
				//daca graful nu este setat (i=1) sau daca s-a schimbat h-ul, fac update
				if(i==1||h[i].value!=h[i-1].value) grow(use[h[i].value+step]);

				//verific daca (sx,sy) si (fx,fy) se alfa in aceeasi padure
				int ind=h[i].idx;

				int sx=P[ind].sx;
				int sy=P[ind].sy;
				int fx=P[ind].fx;
				int fy=P[ind].fy;

				int r_s=root(Convert(sx,sy));
				int r_f=root(Convert(fx,fy));

				if(r_s==r_f) aux[i]=h[i].value+step;
			}

		//actualizez h (vector de pozitii)
		for(int i=1;i<=Q;++i) h[i].value=aux[i];
	}

	//Solutie
	for(int i=1;i<=Q;++i)
		Sol[h[i].idx]=use[h[i].value];

	for(int i=1;i<=Q;++i) cout<<Sol[i]<<'\n';

	return 0;
}