#include<cstdio>
#include<cstring>
#include<iostream>
#include "bits/stdc++.h"
#define LOGN 10
#define MAXN (1<<LOGN)
#define MAXNODES 3*( (1<<(2*LOGN)) / 4 + 100)
#define son(x) (p*4-2+x)//计算儿子公式
using namespace std;
int a[504][504];
struct dateinfo//信息
{
short px,py;//点
int val;//值
void reset(int x){px=0,py=0,val=x;}
};
struct treenode//树上节点
{
dateinfo maxi,mini;
void reset(){maxi.reset(INT_MIN);mini.reset(INT_MAX);}
}nodes[MAXNODES];
treenode* getnode(int id){return &nodes[id];}
struct interval//区间类
{
short l,r;
short mid(){ return (l+r)>>1;}//区间中点
short len(){ return (r-l+(short)1);}//区间长度
interval left(){ return {l,mid()};}//左区间
interval right(){ return {(short)(mid()+1) , r};}//右区间
bool in(short x){ return x>=l&&x<=r;}//判点
bool with(interval t){ return !((l>t.r)||(r<t.l));}//判交
bool include(interval t){ return l<=t.l&&r>=t.r;}//判包含
};
bool build(int p,interval xl,interval yl)//bool判断是否存在该子节点
{
if(xl.len()<=0||yl.len()<=0)return false;
treenode* now = getnode(p);
if(xl.len()==1&&yl.len()==1)
{
now->maxi={xl.l,xl.r,a[xl.l][yl.r]};
now->mini={xl.l,xl.r,a[xl.l][yl.r]};
return true;
}
now->reset();
bool ok[4];
ok[0]=build(son(0),xl.left(),yl.left());
ok[1]=build(son(1),xl.right(),yl.left());
ok[2]=build(son(2),xl.left(),yl.right());
ok[3]=build(son(3),xl.right(),yl.right());
for (int i = 0; i < 4; ++i) {//通过子节点更新now
if(!ok[i])continue;
treenode* son = getnode(son(i));
now->maxi = son->maxi.val > now->maxi.val ? son->maxi : now->maxi;
now->mini = son->mini.val < now->mini.val ? son->mini : now->mini;
}
return true;
}
bool update(int p,interval xl,interval yl,short px,short py,int val)
{
if(xl.len()<=0||yl.len()<=0)return false;
if(!xl.in(px) || !yl.in(py))return true;
treenode* now = getnode(p);
if(xl.len()==1&&yl.len()==1)
{
now->maxi={px,py,val};
now->mini={px,py,val};
return true;
}
now->reset();
bool ok[4];
ok[0]=update(son(0),xl.left(),yl.left(),px,py,val);
ok[1]=update(son(1),xl.right(),yl.left(),px,py,val);
ok[2]=update(son(2),xl.left(),yl.right(),px,py,val);
ok[3]=update(son(3),xl.right(),yl.right(),px,py,val);
for (int i = 0; i < 4; ++i) {//更新now
if(!ok[i])continue;
treenode* son = getnode(son(i));
now->maxi= son->maxi.val > now->maxi.val ? son->maxi : now->maxi;
now->mini= son->mini.val < now->mini.val ? son->mini : now->mini;
}
return true;
}
void query(int p,interval xl,interval yl,interval qx,interval qy,int& ansmax,int& ansmin)
{
if(xl.len()<=0||yl.len()<=0)return ;
if(!xl.with(qx) || !yl.with(qy))return ;
treenode* now = getnode(p);
if(ansmax>=now->maxi.val && ansmin<=now->mini.val)return ;//最值优化
if(qx.include(xl) && qy.include(yl)){
ansmax=max(now->maxi.val,ansmax);
ansmin=min(now->mini.val,ansmin);
return ;
}
if(xl.len()==1&&yl.len()==1){ return;}
query(son(0),xl.left(),yl.left(),qx,qy,ansmax,ansmin);
query(son(1),xl.right(),yl.left(),qx,qy,ansmax,ansmin);
query(son(2),xl.left(),yl.right(),qx,qy,ansmax,ansmin);
query(son(3),xl.right(),yl.right(),qx,qy,ansmax,ansmin);
}
int main()
{
short n;
scanf("%hd",&n);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
scanf("%d",&a[i][j]);
}
}
build(1,{1,n},{1,n});
int q;
scanf("%d",&q);
while(q--)
{
getchar();
char ch;
scanf("%c ",&ch);
if(ch=='q')
{
interval x,y;
scanf("%hd%hd%hd%hd",&x.l,&y.l,&x.r,&y.r);
if(x.l>x.r)swap(x.l,x.r);
if(y.l>y.r)swap(y.l,y.r);
int ansmax=INT_MIN,ansmin=INT_MAX;
query(1,{1,n},{1,n},x,y,ansmax,ansmin);
printf("%d %d\n",ansmax,ansmin);
}
else
{
short x,y;
int val;
scanf("%hd%hd%d",&x,&y,&val);
update(1,{1,n},{1,n},x,y,val);
}
}
}