# 钻石游戏 diamond

### 输入格式:

(1<=x1,x2<=M,1<=y1,y2<=N)表示交换(x1,y1)和(x2,y2)的钻石。

P 行，输出每次交换得到的分值。

### 样例输入:

4 5
1 1 1 3 4
1 1 2 1 2
1 1 1 2 2
3 3 3 4 4
2
2 3 2 4
1 4 1 5



### 样例输出:

9
1


### 提示:

1 1 1 3 4
1 1 1 2 2
1 1 1 2 2
3 3 3 4 4

1 1 1 3 4
1 1 2 1 2
1 1 1 2 2
3 3 3 4 4

40%的数据,M,N<=50,P<=1000
100%的数据,M,N<=500,P<=1000
T2:Mult

#include<bits/stdc++.h>
using namespace std;
int mp[505][505],mp1[505][505],mp2[505][505],mp3[505][505],mp4[505][505],mp5[505][505];
int n,m,chan;
void updata(int x1,int y1,int x2,int y2){
if (x1==x2){
for (int i=1; i<=m; i++)
if (mp[x1][i-1]==mp[x1][i]) mp2[x1][i]=mp2[x1][i-1]+1;
else mp2[x1][i]=1;
for (int i=m; i>=1; i--)
if (mp[x1][i+1]==mp[x1][i]) mp3[x1][i]=mp3[x1][i+1]+1;
else mp3[x1][i]=1;
for (int i=1; i<=n; i++){
if (mp[i][y1]==mp[i-1][y1]) mp1[i][y1]=mp1[i-1][y1]+1;
else mp1[i][y1]=1;
if (mp[i][y2]==mp[i-1][y2]) mp1[i][y2]=mp1[i-1][y2]+1;
else mp1[i][y2]=1;
}
for (int i=n; i>=1; i--){
if (mp[i][y1]==mp[i+1][y1]) mp4[i][y1]=mp4[i+1][y1]+1;
else mp4[i][y1]=1;
if (mp[i][y2]==mp[i+1][y2]) mp4[i][y2]=mp4[i+1][y2]+1;
//这里的mp4[i][y2]=mp4[i+1][y2]+1;之前打成了mp4[i][y2]==mp4[i+1][y2]+1;
//死活找不出来
else mp4[i][y2]=1;
}
}
else if (y1==y2){
for (int i=1; i<=n; i++)
if (mp[i][y1]==mp[i-1][y1]) mp1[i][y1]=mp1[i-1][y1]+1;
else mp1[i][y1]=1;
for (int i=n; i>=1; i--)
if (mp[i][y1]==mp[i+1][y1]) mp4[i][y1]=mp4[i+1][y1]+1;
else  mp4[i][y1]=1;
for (int i=1; i<=m; i++){//这里的循环之前想要减少一点……结果……减错了
if (mp[x1][i-1]==mp[x1][i]) mp2[x1][i]=mp2[x1][i-1]+1;
else mp2[x1][i]=1;
if (mp[x2][i-1]==mp[x2][i]) mp2[x2][i]=mp2[x2][i-1]+1;
else mp2[x2][i]=1;
}
for (int i=m; i>=1; i--){
if (mp[x1][i+1]==mp[x1][i]) mp3[x1][i]=mp3[x1][i+1]+1;
else mp3[x1][i]=1;
if (mp[x2][i+1]==mp[x2][i]) mp3[x2][i]=mp3[x2][i+1]+1;
else mp3[x2][i]=1;
}
}
}
int main(){
cin>>n>>m;
for (int i=1; i<=n; i++){
for (int l=1; l<=m; l++){
cin>>mp[i][l];
if (mp[i-1][l]==mp[i][l]) mp1[i][l]=mp1[i-1][l]+1;
else mp1[i][l]=1;
if (mp[i][l-1]==mp[i][l]) mp2[i][l]=mp2[i][l-1]+1;
else mp2[i][l]=1;
}
}
for (int i=n; i>=1; i--){
for (int l=m; l>=1; l--){
if (mp[i][l+1]==mp[i][l]) mp3[i][l]=mp3[i][l+1]+1;
else mp3[i][l]=1;
if (mp[i+1][l]==mp[i][l]) mp4[i][l]=mp4[i+1][l]+1;
else mp4[i][l]=1;
}
}
cin>>chan;
for (int i=1; i<=chan; i++){
int x1,x2,y1,y2;
cin>>x1>>y1>>x2>>y2;
swap(mp[x1][y1],mp[x2][y2]);
updata(x1,y1,x2,y2);
if (x1==x2){
while (mp[x1][pos]==mp[x1][min(y1,y2)] && pos>=1){
//				mina=min(mina,mp1[x1][pos]+mp4[x1][pos]-1);
//                              这里是一个非常关键的错误，关系到理解题意。
//                              大致意思就是如果是左右交换就往左右扫，用这一条路最小高度乘长度更新最大面积
//                              如果上下更新就往上下扫，用最小宽度乘高度更新最大面积
//                              原本我是非常naive地算最小高度这个东西的，就是上加下-1，但是！这样是错的
//                              应该分别用上和下的最小值来更新最小高度，而不是看总和。。。
minau=min(minau,mp1[x1][pos]);
pos--;
}
while (mp[x1][pos]==mp[x1][max(y1,y2)] && pos<=m){
//				mina=min(mina,mp1[x1][pos]+mp4[x1][pos]-1);
minau=min(minau,mp1[x1][pos]);
pos++;
}
cout<<maxn<<endl;
}
else if (y1==y2){
int pos=min(x1,x2),minal=1e8,minar=1e8,maxn=-1;
while (mp[pos][y1]==mp[min(x1,x2)][y1] && pos>=1){
//				mina=min(mina,mp2[pos][y1]+mp3[pos][y1]-1);
minal=min(minal,mp2[pos][y1]);
minar=min(minar,mp3[pos][y1]);
maxn=max(maxn,(min(x1,x2)-pos+1)*(minal+minar-1));
pos--;
}
pos=max(x1,x2);minal=1e8;minar=1e8;
while (mp[pos][y1]==mp[max(x1,x2)][y1] && pos<=n){
//				mina=min(mina,mp2[pos][y1]+mp3[pos][y1]-1);
minal=min(minal,mp2[pos][y1]);
minar=min(minar,mp3[pos][y1]);
maxn=max(maxn,(pos-max(x1,x2)+1)*(minal+minar-1));
pos++;
}
cout<<maxn<<endl;
}
}
return 0;
}