Uva – 11297 – Census

Approach : Segment Tree , Sqrt-Decomposition..

First Solution :

This is typical 2D segment tree problem. Just write the code correctly and good enough to get AC
I used two array , One to store Maximum , One to Minimum ..


#include <bits/stdc++.h>
using namespace std;

/*------- Constants---- */
#define LMT				605
#define ll				long long
#define ull				unsigned long long
#define mod				1000000007
#define MEMSET_INF		63
#define MEM_VAL			1061109567
#define FOR(i,n)			for( int i=0 ; i < n ; i++ )
#define mp(i,j)			make_pair(i,j)
#define lop(i,a,b)		for( int i = (a) ; i < (b) ; i++)
#define pb(a)			push_back((a))
#define gc				getchar_unlocked
#define PI				acos(-1.0)
#define inf				1<<30
#define lc				((n)<<1)
#define rc				((n)<<1 |1)
#define msg(x)			cout<<x<<endl;

/*---- short Cuts ------- */
#define ms(ara_name,value) memset(ara_name,value,sizeof(ara_name))
typedef pair<int, int> ii;
typedef vector<int > vi ;
/*------ template functions ------ */
inline void sc(int &x)
{
	register int c = gc();
	x = 0;
	int neg = 0;
	for(;((c<48 | c>57) && c != '-');c = gc());
	if(c=='-') {neg=1;c=gc();}
	for(;c>47 && c<58;c = gc()) {x = (x<<1) + (x<<3) + c - 48;}
	if(neg) x=-x;
}

template <class T> inline T bigmod(T p,T e,T M){
	ll ret = 1;
	for(; e > 0; e >>= 1){
		if(e & 1) ret = (ret * p) % M;
		p = (p * p) % M;
	} return (T)ret;
}
template <class T> inline T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template <class T> inline T modinverse(T a,T M){return bigmod(a,M-2,M);}

/*************************** END OF TEMPLATE ****************************/

int t[4*LMT][4*LMT];
int p[4*LMT][4*LMT];
int a[LMT][LMT];
int m , n ;
void build_y (int vx, int lx, int rx, int vy, int ly, int ry) {
	if (ly == ry)
		if (lx == rx){
			t[vx][vy] = a[lx][ly];
			p[vx][vy] = a[lx][ly];
		}
			
		else {
			t[vx][vy] = max(t[vx*2][vy] , t[vx*2+1][vy] );
			p[vx][vy] = min(p[vx*2][vy] , p[vx*2+1][vy] );
		}
	
		else {
			int my = (ly + ry) / 2;
			build_y (vx, lx, rx, vy*2, ly, my);
			build_y (vx, lx, rx, vy*2+1, my+1, ry);
			t[vx][vy] = max(t[vx][vy *2] , t[vx][vy *2 + 1]);
			p[vx][vy] = min(p[vx][vy *2] , p[vx][vy *2 + 1]);
		}
}

void build_x (int vx, int lx, int rx) {
	if (lx != rx) {
		int mx = (lx + rx) / 2;
		build_x (vx*2, lx, mx);
		build_x (vx*2+1, mx+1, rx);
	}
	build_y (vx, lx, rx, 1, 0, m-1);
}


void update_y (int vx, int lx, int rx, int vy, int ly, int ry, int x, int y, int new_val) {
	if (ly == ry) {
		if (lx == rx){
			t[vx][vy] = new_val;
			p[vx][vy] = new_val;
		}
		else {
			t[vx][vy] = max(t[vx*2][vy] , t[vx*2+1][vy] );
			p[vx][vy] = min(p[vx*2][vy] , p[vx*2+1][vy] );
		}
		
	}
	else {
		int my = (ly + ry) / 2;
		if (y <= my) update_y (vx, lx, rx, vy*2, ly, my, x, y, new_val);
		else update_y (vx, lx, rx, vy*2+1, my+1, ry, x, y, new_val);
		
		t[vx][vy] = max(t[vx][vy *2] , t[vx][vy *2 + 1]);
		p[vx][vy] = min(p[vx][vy *2] , p[vx][vy *2 + 1]);
	}
}

void update_x (int vx, int lx, int rx, int x, int y, int new_val) {
	if (lx != rx) {
		int mx = (lx + rx) / 2;
		if (x <= mx) update_x (vx*2, lx, mx, x, y, new_val);
		else update_x (vx*2+1, mx+1, rx, x, y, new_val);
	}
	update_y (vx, lx, rx, 1, 0, m-1, x, y, new_val);
}


ii query_y (int vx, int vy, int tly, int try_, int ly, int ry) {
	
	if (ly > ry) return ii(-1,inf );
	
	if (ly == tly && try_ == ry) return ii( t[vx][vy] ,p[vx][vy]);
	
	int tmy = (tly + try_) / 2;
	
	ii r1 = query_y (vx, vy*2, tly, tmy, ly, min(ry,tmy));
	ii r2 = query_y (vx, vy*2+1, tmy+1, try_, max(ly,tmy+1), ry);
	
	return ii( max(r1.first , r2.first) , min(r1.second, r2.second)) ;
	
}

ii query_x (int vx, int tlx, int trx, int lx, int rx, int ly, int ry) {
	if (lx > rx)
		return ii(-1,inf );
	if (lx == tlx && trx == rx)
		return query_y (vx, 1, 0, m-1, ly, ry);
	int tmx = (tlx + trx) / 2;
	
	ii r1 = query_x (vx*2, tlx, tmx, lx, min(rx,tmx), ly, ry);
	ii r2 = query_x (vx*2+1, tmx+1, trx, max(lx,tmx+1), rx, ly, ry);
	
	return ii( max(r1.first , r2.first) , min(r1.second, r2.second)) ;
}

int val ;

int main()
{
	
	
	

	int  q ;
	sc(n); sc(m);
	FOR(i , n) FOR(j , m) sc(a[i][j]);
	
	
	build_x(1, 0 , n-1);
	
	sc(q);
	
	char ch ;
	int x1,  x2 , y1 , y2;
	while (q -- ) {
		do {
			ch = gc();
		} while (ch =='\n'||ch =='\0');
		
		if(ch == 'q') {
			sc(x1) ; sc(y1) ;sc(x2);sc(y2);
			x1 -- , y1 -- ,x2 -- , y2 --;
			ii r = query_x( 1, 0 , n -1 , x1 , x2 , y1 , y2);
			printf("%d %d\n" ,r.first , r.second);
		}
		else {
			sc(x1) ;sc(y1 );sc(val);
			x1 -- , y1--;
			update_x(1, 0, n-1 ,x1 , y1,val);
		}
		
	}
	
	return 0;
}

Second Try : Sqrt- Decompostion.

1. We can divide the whole square / Rectangle in some smaller block which dimension is sqrt(n) x sqrt(n)
2. We store The minimum & maximum of this block in a 2D array ..
3. For updating a point We need just to update the block , where it belongs,
4. For query , We need to traverse thorough lot of case …

Please See the implementation And try to understand how the whole interval is covered.


#include <bits/stdc++.h>
using namespace std;

/*------- Constants---- */
#define LMT				600
#define ll				long long
#define ull				unsigned long long
#define mod				1000000007
#define MEMSET_INF		63
#define MEM_VAL			1061109567
#define FOR(i,n)			for( int i=0 ; i < n ; i++ )
#define mp(i,j)			make_pair(i,j)
#define lop(i,a,b)		for( int i = (a) ; i < (b) ; i++)
#define pb(a)			push_back((a))
#define gc				getchar_unlocked
#define PI				acos(-1.0)
#define inf				1<<30
#define lc				((n)<<1)
#define rc				((n)<<1 |1)
#define msg(x)			cout<<x<<endl;

/*---- short Cuts ------- */
#define ms(ara_name,value) memset(ara_name,value,sizeof(ara_name))
typedef pair<int, int> ii;
typedef vector<int > vi ;
/*------ template functions ------ */
inline void sc(int &x)
{
	register int c = gc();
	x = 0;
	int neg = 0;
	for(;((c<48 | c>57) && c != '-');c = gc());
	if(c=='-') {neg=1;c=gc();}
	for(;c>47 && c<58;c = gc()) {x = (x<<1) + (x<<3) + c - 48;}
	if(neg) x=-x;
}

template <class T> inline T bigmod(T p,T e,T M){
	ll ret = 1;
	for(; e > 0; e >>= 1){
		if(e & 1) ret = (ret * p) % M;
		p = (p * p) % M;
	} return (T)ret;
}
template <class T> inline T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template <class T> inline T modinverse(T a,T M){return bigmod(a,M-2,M);}

/*************************** END OF TEMPLATE ****************************/

int block ;
int iA[LMT][LMT];
int partMax[35][35];
int partMin[35][35];
int val;

int main()
{
	
	int n , m ;
	sc(n ); sc(m );
	
	block = sqrt(n) + 1 ;
	FOR(i, block + 5 ){
		FOR(j , block + 5 ){
			partMax[i][j] = -1;
			partMin[i][j] = inf;
		}
	}
	FOR(i, n) {
		int x  = i / block;
		FOR(j, m){
			sc(iA[i][j]);
			partMax [x][j/block] = max( partMax[x][j / block] , iA[i][j] );
			partMin [x][j/block] = min( partMin[x][j / block] , iA[i][j] );
		}
	}
	
	int q , x1 , y1 , x2 , y2 ;
	char ch ;
	sc(q);
	int cnt= 0;
	while (q -- ) {
		do {
			ch = gc();
		} while (ch =='\n'||ch =='\0');
		
		if(ch == 'q') {
			++cnt;
			
			if(cnt == 12 ) {
				
				//cout<<""<<endl;
			}
			
			sc(x1) ;sc(y1) ;sc(x2) ; sc(y2);
			x1 -- , y1 -- , x2 -- , y2 --;
			
			int iMac = -1 , iMin = inf ;
			while(x1 <= x2 && x1 % block != 0 ){
				
				for(int j = y1 ; j <= y2 ; j ++ ) {
					iMac = max(iMac , iA[x1][j]);
					iMin = min(iMin , iA[x1][j]);
				}
				x1 ++;
			}
			
			
			while (x1 + block - 1 <= x2 ) {
				
				int y = y1;
				
				while (y  <= y2 && y % block != 0 ) {
					
					for(int i = x1; i < x1 + block ; i ++ ) {
						iMac = max(iMac , iA[i][y]);
						iMin = min(iMin , iA[i][y]);
					}
					y ++;
				}
				while (y + block -1 <= y2 ) {
					iMac = max(iMac , partMax[x1/block][y /block]);
					iMin = min(iMin , partMin[x1/block][y/block]);
					y += block;
				}
				while( y <= y2 ) {
					for(int i = x1; i < x1 + block ; i ++ ) {
						iMac = max(iMac , iA[i][y]);
						iMin = min(iMin , iA[i][y]);
					}
					y ++;
				}
				
				x1 = x1 + block;
			}
			
			for(int i = x1 ; i <= x2; i ++ ){
				for (int j = y1 ; j <= y2 ; j ++ ) {
					iMac = max(iMac , iA[i][j]);
					iMin = min(iMin , iA[i][j]);
				}
			}
			
			printf("%d %d\n",iMac ,  iMin);
			
			
		}
		else {
			
			
			sc(x1) ; sc(y1 ); sc(val);
			x1 -- ;
			y1 -- ;
			iA[x1][y1] = val;
			
			int i = (x1 / block ) * block;
			int j = (y1 / block ) * block;
			
			partMax[i/block][j /block] = 0;
			partMin[i/block][j/block] = inf;
			for(int L = i ; L < i+ block ; L ++ ) {
				int x = L / block;
				for (int R = j ; R < j + block ; R ++ ) {
					partMax[x][R / block] = max ( partMax[x][R /block ] , iA[L][R]);
					partMin[x][R / block] = min ( partMin[x][R /block ] , iA[L][R]);
				}
			}
		}
	}
	
	return 0;
}

Third Approach :
Maintain 1D segment tree for Each Row.
This one is the easiest one. And also get AC in given time limit..
1. For each row, Maintain a segment tree to so that you can find minimum and maximum value in a given interval.
2. For query operation, iterate through the row , and find the minimum and Maximum Value in the given (y1,y2) interval

See the implementation:



#include <bits/stdc++.h>
using namespace std;

/*------- Constants---- */
#define LMT				605
#define ll				long long
#define ull				unsigned long long
#define mod				1000000007
#define MEMSET_INF		63
#define MEM_VAL			1061109567
#define FOR(i,n)			for( int i=0 ; i < n ; i++ )
#define mp(i,j)			make_pair(i,j)
#define lop(i,a,b)		for( int i = (a) ; i < (b) ; i++)
#define pb(a)			push_back((a))
#define gc				getchar_unlocked
#define PI				acos(-1.0)
#define inf				1<<30
#define lc				((n)<<1)
#define rc				((n)<<1 |1)
#define msg(x)			cout<<x<<endl;

/*---- short Cuts ------- */
#define ms(ara_name,value) memset(ara_name,value,sizeof(ara_name))
typedef pair<int, int> ii;
typedef vector<int > vi ;
/*------ template functions ------ */
inline void sc(int &x)
{
	register int c = gc();
	x = 0;
	int neg = 0;
	for(;((c<48 | c>57) && c != '-');c = gc());
	if(c=='-') {neg=1;c=gc();}
	for(;c>47 && c<58;c = gc()) {x = (x<<1) + (x<<3) + c - 48;}
	if(neg) x=-x;
}

template <class T> inline T bigmod(T p,T e,T M){
	ll ret = 1;
	for(; e > 0; e >>= 1){
		if(e & 1) ret = (ret * p) % M;
		p = (p * p) % M;
	} return (T)ret;
}
template <class T> inline T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template <class T> inline T modinverse(T a,T M){return bigmod(a,M-2,M);}

/*************************** END OF TEMPLATE ****************************/

ii seg[LMT][4*LMT];
int row;
int val;

int iA[LMT][LMT];

void build(int n,int b,int e)
{
	if( b == e) {
		seg[row][n] = ii(iA[row][b] , iA[row][b]);
		return;
	}
	
	int mid = (b+e)/2;
	build(lc, b, mid);
	build(rc, mid +1 , e);
	
	seg[row][n].first =  max( seg[row][lc].first , seg[row][rc].first );
	seg[row][n].second = min (seg[row][lc].second , seg[row][rc].second);
	
	
}

void updt(int n,int b,int e,int pos)
{
	if( b == e && b == pos ) {
		seg[row][n].first = val;
		seg[row][n].second = val;
		return;
	}
	
	int mid = (b+e)/2;
	
	if( pos <= mid ) updt(lc , b , mid , pos);
	else updt(rc, mid + 1, e, pos);
	
	seg[row][n].first =  max( seg[row][lc].first , seg[row][rc].first );
	seg[row][n].second = min (seg[row][lc].second , seg[row][rc].second);
	
}

ii query(int n,int b,int e ,int i , int j )
{
	if( b > j || e < i) return ii(-1,inf);
	if( b >= i && e <= j ) {
		return seg[row][n];
	}
	int mid = (b+e) / 2;
	ii r1 = query(lc , b , mid, i, j);
	ii r2 = query(rc , mid + 1, e, i , j);
	
	return ii(max(r1.first , r2.first) , min(r1.second , r2.second));
}


int main()
{
	
	
	int n , m ,q ;
	sc(n) ;sc(m);
	FOR(i, n){
		row = i;
		FOR(j, m) {
			sc(iA[i][j]);
		}
		build(1, 0 , m -1);
	}
	
	sc(q);
	char ch;
	int x1, x2 , y1 , y2;
	
	while (q -- ) {
		do {
			ch =gc();
		} while (ch == '\n' || ch =='\0');
		
		if(ch =='q'){
			sc(x1) ;sc(y1) ;sc(x2); sc(y2);
			x1--,y1--,x2--,y2--;
			ii r = ii(-1,inf);
			for(int i = x1; i <= x2; i ++ ) {
				row = i ;
				ii r1 = query(1, 0, m-1, y1 , y2);
				r.first = max(r.first , r1.first);
				r.second = min(r.second , r1.second);
			}
			
			printf("%d %d\n" , r.first , r.second);
		}
		if( ch =='c'){
			sc(x1);sc(y1) ;sc(val);
			x1 -- ,y1--;
			row = x1;
			updt(1, 0, n-1, y1);
		}
	}
	return 0;
}

I hope there may be other methods to solve this problem . Explore them..

Remark :
2D segment Tree is the best solution
Sqrt Decomposition
Row Based 1D segment Tree

Leave a comment