#include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld =long double;
const ld eps = 1e-9;

#define Seg_Max_N (1<<18) 

struct aa {
	long long int amin;
	long long int min_num;

	long long int amax;
	long long int max_num;
};

typedef aa Value1;
typedef long long int Value2;
const Value1 Zero1 = aa{ 0,1,0,1 };
const Value2 Zero2 =0;

struct Node {
	Value1 sum;//更新された値. この値を参照する時は評価が完全に完了しているようにする.
	Value2 lazy;	//遅延されている値を保存している
	Node() :sum(Zero1) {
		lazy = Zero2;
	}
};
struct lazy_segtree {
	int N;
	vector<Node>dat;
	lazy_segtree(int n) :N(1) {
		while (N < n) N *= 2;
		dat.resize(2 * N);
	}

	Value2 lazy_connect(const Value2 l, const Value2 r) {
		return l+r;
	}

	void lazy_func(const int k, const int a, const int b) {
		
		dat[k].sum.amin += dat[k].lazy;
		dat[k].sum.amax+=dat[k].lazy;
		
	}

	Value1 connect(const Value1 l, const Value1 r) {
		aa naa;
		if (l.amin == r.amin) {
			naa.amin = l.amin;
			naa.min_num = l.min_num + r.min_num;
		}
		else if (l.amin > r.amin) {
			naa.amin = r.amin;
			naa.min_num = r.min_num;
		}
		else {
			naa.amin = l.amin;
			naa.min_num = l.min_num;
		}

		if (l.amax == r.amax) {
			naa.amax = l.amax;
			naa.max_num = l.max_num + r.max_num;
		}
		else if (l.amax < r.amax) {
			naa.amax = r.amax;
			naa.max_num = r.max_num;
		}
		else {
			naa.amax = l.amax;
			naa.max_num = l.max_num;
		}
		return naa;
	}

	// inlineつけないと大変なことになるよ!(遅い)
	inline void lazy_evaluate_node(int k, int a, int b) {
		lazy_func(k, a, b);
		if (k < N) { // 2*k(左の子番号) < 2*N (節点の数) のイメージで. 末端ノードじゃなきゃ伝搬するのと等価.
			dat[2 * k].lazy = lazy_connect(dat[2 * k].lazy, dat[k].lazy);	//次は君が伝搬してね☆って感じ.
			dat[2 * k + 1].lazy = lazy_connect(dat[2 * k + 1].lazy, dat[k].lazy);
		}
		dat[k].lazy = Zero2;
	}

	inline void update_node(int k) { // kの子が既に評価されていることが前提. 末端以外のときしか呼び出さないような位置に書くのでif文要らない.
		dat[k].sum = connect(dat[2 * k].sum, dat[2 * k + 1].sum);

	}

	// update(l,r,v) := [l,r)を更新する. 区間は0-indexed.
	void update(int l, int r, Value2 v, int k = 1, int a = 0, int b = -1) {
		if (b == -1)b = N;
		if (l < 0 || r < 0)assert(false);
		lazy_evaluate_node(k, a, b); 	// とりあえず辿ったノードは都合がいいので伝搬しとけ精神.

		if (b <= l || r <= a) //[a,b)と[l,r)が交差している場合
			return;
		if (l <= a && b <= r) { // [l,r)が[a,b)を完全に含んでいる場合
			dat[k].lazy = lazy_connect(dat[k].lazy, v);
			lazy_evaluate_node(k, a, b); //一回遅延評価しとかないと都合悪いので.
			return;
		}

		int m = (a + b) / 2;
		update(l, r, v, 2 * k, a, m);
		update(l, r, v, 2 * k + 1, m, b);
		update_node(k);
	}
	//get(l,r) := [l,r)に対するクエリの答えを得る. 区間は0-indexed.
	Value1 get(int l, int r, int k = 1, int a = 0, int b = -1) {
		if (b == -1)b = N;

		if (l < 0 || r<0)assert(false);
		lazy_evaluate_node(k, a, b); // とりあえず辿ったノードは都合がいいので伝搬しとけ精神.

		if (b <= l || r <= a) //[a,b)と[l,r)が交差している場合
			return aa{static_cast<long long int>(1e18),0,static_cast<long long int>(-1e18),0 };

		if (l <= a && b <= r) { // [l,r)が[a,b)を完全に含んでいる場合
			return dat[k].sum;
		}

		int m = (a + b) / 2;
		Value1 vl = get(l, r, 2 * k, a, m);
		Value1 vr = get(l, r, 2 * k + 1, m, b);
		update_node(k);
		return connect(vl, vr);
	}
};

int main()
{
	int H,W,Q;cin>>H>>W>>Q;
	vector<int>as(H),bs(W);
	for(int i=0;i<H;++i)cin>>as[i];
	for(int i=0;i<W;++i)cin>>bs[i];
	lazy_segtree aseg(H),bseg(W);
	for (int i = 0; i < H; ++i) {
		aseg.update(i,i+1, as[i]);
	}
	for (int i = 0; i < W; ++i) {
		bseg.update(i,i+1, bs[i]);
	}
	while (Q--) {
		int type;cin>>type;
		if (type == 1) {
			int a,b,x;cin>>a>>b>>x;a--;
			aseg.update(a,b,x);
		}
		else if (type == 2) {
			int a,b,x;cin>>a>>b>>x;a--;
			bseg.update(a,b,x);
		}
		else {
			int a,b,c,d;cin>>a>>b>>c>>d;
			a--;c--;
			auto a_aa=aseg.get(a,b);
			auto b_aa=bseg.get(c,d);

			map<long long int,long long int>mp;

			if (a_aa.amin != a_aa.amax) {
				if (b_aa.amin != b_aa.amax) {

					mp[a_aa.amin*b_aa.amin] += a_aa.min_num*b_aa.min_num;
					mp[a_aa.amax*b_aa.amin] += a_aa.max_num*b_aa.min_num;
					mp[a_aa.amin*b_aa.amax] += a_aa.min_num*b_aa.max_num;
					mp[a_aa.amax*b_aa.amax] += a_aa.max_num*b_aa.max_num;
				}
				else {

					mp[a_aa.amin*b_aa.amin] += a_aa.min_num*b_aa.min_num;
					mp[a_aa.amax*b_aa.amin] += a_aa.max_num*b_aa.min_num;
				}
			}
			else {
				if (b_aa.amin != b_aa.amax) {

					mp[a_aa.amin*b_aa.amin] += a_aa.min_num*b_aa.min_num;
					mp[a_aa.amin*b_aa.amax] += a_aa.min_num*b_aa.max_num;
				}
				else {
					mp[a_aa.amin*b_aa.amin] += a_aa.min_num*b_aa.min_num;
				}
			}

			auto it=mp.begin();
			auto jt=prev(mp.end());

			if (type == 3) {
				long long int ans_num,ans_cnt;
				if (it->first == 0) {
					if (a_aa.amin == 0 && b_aa.amin == 0) {
						ans_cnt = (b - a)*b_aa.min_num + (d - c)*a_aa.min_num - a_aa.min_num*b_aa.min_num;
					}
					else if (a_aa.amin == 0) {
						ans_cnt=(d-c)*a_aa.min_num;
					}
					else if(b_aa.amin==0){
						ans_cnt=(b-a)*b_aa.min_num;
					}
					else {
						swap(a_aa.amin,a_aa.amax);
						swap(a_aa.min_num,a_aa.max_num);
						swap(b_aa.amin,b_aa.amax);
						swap(b_aa.min_num, b_aa.max_num);

						if (a_aa.amin == 0 && b_aa.amin == 0) {
							ans_cnt = (b - a)*b_aa.min_num + (d - c)*a_aa.min_num - a_aa.min_num*b_aa.min_num;
						}
						else if (a_aa.amin == 0) {
							ans_cnt = (d - c)*a_aa.min_num;
						}
						else if (b_aa.amin == 0) {
							ans_cnt = (b - a)*b_aa.min_num;
						}
						else {
							assert(false);
						}
					}
				}
				else {
					ans_cnt=it->second;
				}
				cout<<it->first<<" "<<ans_cnt<<endl;
			}
			else {
				long long int ans_num, ans_cnt;
				swap(b_aa.amin,b_aa.amax);
				swap(b_aa.min_num,b_aa.max_num);
				if (jt->first == 0) {
					if (a_aa.amin == 0 && b_aa.amin == 0) {
						ans_cnt = (b - a)*b_aa.min_num + (d - c)*a_aa.min_num - a_aa.min_num*b_aa.min_num;
					}
					else if (a_aa.amin == 0) {
						ans_cnt = (d - c)*a_aa.min_num;
					}
					else if (b_aa.amin == 0) {
						ans_cnt = (b - a)*b_aa.min_num;
					}
					else {
						swap(a_aa.amin, a_aa.amax);
						swap(a_aa.min_num, a_aa.max_num);
						swap(b_aa.amin, b_aa.amax);
						swap(b_aa.min_num, b_aa.max_num);

						if (a_aa.amin == 0 && b_aa.amin == 0) {
							ans_cnt = (b - a)*b_aa.min_num + (d - c)*a_aa.min_num - a_aa.min_num*b_aa.min_num;
						}
						else if (a_aa.amin == 0) {
							ans_cnt = (d - c)*a_aa.min_num;
						}
						else if (b_aa.amin == 0) {
							ans_cnt = (b - a)*b_aa.min_num;
						}
						else {
							assert(false);
						}
					}
				}
				else {
					ans_cnt = jt->second;
				}
				cout << jt->first << " " << ans_cnt << endl;
			}
		}
	}
	return 0;
}

### Prompt

Please create a solution in cpp to the following problem:

Problem

Given a sequence $ A $ of length $ H $ and a sequence $ B $ of length $ W $.

Define the matrix $ C $ consisting of $ H $ rows and $ W $ columns as follows.
$ C_ {i, j} = A_i \ times B_j (1 \ leq i \ leq H, 1 \ leq j \ leq W) $

Process the following four types of queries a total of $ Q $ times.

Query 1
$ 1 $ $ a $ $ b $ $ v $
$ A_i (a \ leq i \ leq b) Add $ v $ to $

Query 2
$ 2 $ $ c $ $ d $ $ v $
$ B_j (c \ leq j \ leq d) Add $ v $ to $

Query 3
$ 3 $ $ a $ $ b $ $ c $ $ d $
$ C_ {i, j} (a \ leq i \ leq b, c \ leq j \ leq d) Output the minimum value of $ and its number

Query 4
$ 4 $ $ a $ $ b $ $ c $ $ d $
$ C_ {i, j} (a \ leq i \ leq b, c \ leq j \ leq d) Output the maximum value of $ and its number

For details, refer to sample input / output.

Constraints

The input satisfies the following conditions.

* $ 1 \ leq H, W, Q \ leq 10 ^ 5 $
* $ -1000 \ leq A_i \ leq 1000 $
* $ -1000 \ leq B_j \ leq 1000 $



For each query, the input satisfies the following conditions.


* $ 1 \ leq a \ leq b \ leq H $
* $ 1 \ leq c \ leq d \ leq W $
* $ -1000 \ leq v \ leq 1000 $

Input

The input is given in the following format.


$ H $ $ W $ $ Q $
$ A_1 $ $ A_2 $ ... $ A_H $
$ B_1 $ $ B_2 $ ... $ B_W $
$ query_1 $
$ query_2 $
...
$ query_Q $


Each query is given in one of the following four formats.


$ 1 $ $ a $ $ b $ $ v $
$ 2 $ $ c $ $ d $ $ v $
$ 3 $ $ a $ $ b $ $ c $ $ d $
$ 4 $ $ a $ $ b $ $ c $ $ d $


All inputs are given as integers.
$ H $, $ W $, $ Q $ are given on the first line, separated by blanks.
In the second row, the element $ A_i $ ($ 1 \ leq i \ leq H $) of the sequence $ A $ is given, separated by blanks.
In the third row, the element $ B_j $ ($ 1 \ leq j \ leq W $) of the sequence $ B $ is given, separated by blanks.
Queries are given on the 4th and subsequent $ Q $ lines, separated by line breaks.
All numbers in each query are separated by blanks.

Output

For each query 3 and query 4, output the value and number on one line, separated by blanks.

Examples

Input

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


Output

4 1
9 1
1 1
1 1
2 2
12 1


Input

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


Output

1 16
1 16
1 4
4 4


Input

4 4 7
0 1 0 1
1 0 1 0
3 2 4 1 3
4 1 4 1 4
1 1 4 -1
3 1 3 1 3
1 3 3 2
2 3 3 -2
3 2 4 2 4


Output

0 5
1 4
-1 4
-1 1


Input

36 4 20
-523 -460 -536 -885 652 782 513 -558 -521 -808 124 -708 -943 52 -856 -755 -958 913 380 -767 373 -731 -492 213 538 392 -39 509 -840 135 78 -285 -241 522 -572 -915
-691 -16 812 -385
4 7 17 4 4
3 24 33 1 1
4 3 35 2 4
3 28 32 4 4
2 3 3 438
3 7 15 1 1
4 2 17 4 4
3 24 28 2 4
4 15 16 4 4
4 18 29 1 1
3 24 27 2 4
2 2 3 -828
3 18 23 3 3
1 27 31 -701
2 2 3 298
1 21 32 237
2 3 3 -71
1 14 29 772
4 13 19 3 3
3 19 34 1 2


Output

368830 1
-371758 1
741356 1
-195965 1
-354483 1
368830 1
-207130 1
329560 1
580440 1
-207130 1
-323674 1
1093565 1
-1068977 1

### Response

```cpp
#include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld =long double;
const ld eps = 1e-9;

#define Seg_Max_N (1<<18) 

struct aa {
	long long int amin;
	long long int min_num;

	long long int amax;
	long long int max_num;
};

typedef aa Value1;
typedef long long int Value2;
const Value1 Zero1 = aa{ 0,1,0,1 };
const Value2 Zero2 =0;

struct Node {
	Value1 sum;//更新された値. この値を参照する時は評価が完全に完了しているようにする.
	Value2 lazy;	//遅延されている値を保存している
	Node() :sum(Zero1) {
		lazy = Zero2;
	}
};
struct lazy_segtree {
	int N;
	vector<Node>dat;
	lazy_segtree(int n) :N(1) {
		while (N < n) N *= 2;
		dat.resize(2 * N);
	}

	Value2 lazy_connect(const Value2 l, const Value2 r) {
		return l+r;
	}

	void lazy_func(const int k, const int a, const int b) {
		
		dat[k].sum.amin += dat[k].lazy;
		dat[k].sum.amax+=dat[k].lazy;
		
	}

	Value1 connect(const Value1 l, const Value1 r) {
		aa naa;
		if (l.amin == r.amin) {
			naa.amin = l.amin;
			naa.min_num = l.min_num + r.min_num;
		}
		else if (l.amin > r.amin) {
			naa.amin = r.amin;
			naa.min_num = r.min_num;
		}
		else {
			naa.amin = l.amin;
			naa.min_num = l.min_num;
		}

		if (l.amax == r.amax) {
			naa.amax = l.amax;
			naa.max_num = l.max_num + r.max_num;
		}
		else if (l.amax < r.amax) {
			naa.amax = r.amax;
			naa.max_num = r.max_num;
		}
		else {
			naa.amax = l.amax;
			naa.max_num = l.max_num;
		}
		return naa;
	}

	// inlineつけないと大変なことになるよ!(遅い)
	inline void lazy_evaluate_node(int k, int a, int b) {
		lazy_func(k, a, b);
		if (k < N) { // 2*k(左の子番号) < 2*N (節点の数) のイメージで. 末端ノードじゃなきゃ伝搬するのと等価.
			dat[2 * k].lazy = lazy_connect(dat[2 * k].lazy, dat[k].lazy);	//次は君が伝搬してね☆って感じ.
			dat[2 * k + 1].lazy = lazy_connect(dat[2 * k + 1].lazy, dat[k].lazy);
		}
		dat[k].lazy = Zero2;
	}

	inline void update_node(int k) { // kの子が既に評価されていることが前提. 末端以外のときしか呼び出さないような位置に書くのでif文要らない.
		dat[k].sum = connect(dat[2 * k].sum, dat[2 * k + 1].sum);

	}

	// update(l,r,v) := [l,r)を更新する. 区間は0-indexed.
	void update(int l, int r, Value2 v, int k = 1, int a = 0, int b = -1) {
		if (b == -1)b = N;
		if (l < 0 || r < 0)assert(false);
		lazy_evaluate_node(k, a, b); 	// とりあえず辿ったノードは都合がいいので伝搬しとけ精神.

		if (b <= l || r <= a) //[a,b)と[l,r)が交差している場合
			return;
		if (l <= a && b <= r) { // [l,r)が[a,b)を完全に含んでいる場合
			dat[k].lazy = lazy_connect(dat[k].lazy, v);
			lazy_evaluate_node(k, a, b); //一回遅延評価しとかないと都合悪いので.
			return;
		}

		int m = (a + b) / 2;
		update(l, r, v, 2 * k, a, m);
		update(l, r, v, 2 * k + 1, m, b);
		update_node(k);
	}
	//get(l,r) := [l,r)に対するクエリの答えを得る. 区間は0-indexed.
	Value1 get(int l, int r, int k = 1, int a = 0, int b = -1) {
		if (b == -1)b = N;

		if (l < 0 || r<0)assert(false);
		lazy_evaluate_node(k, a, b); // とりあえず辿ったノードは都合がいいので伝搬しとけ精神.

		if (b <= l || r <= a) //[a,b)と[l,r)が交差している場合
			return aa{static_cast<long long int>(1e18),0,static_cast<long long int>(-1e18),0 };

		if (l <= a && b <= r) { // [l,r)が[a,b)を完全に含んでいる場合
			return dat[k].sum;
		}

		int m = (a + b) / 2;
		Value1 vl = get(l, r, 2 * k, a, m);
		Value1 vr = get(l, r, 2 * k + 1, m, b);
		update_node(k);
		return connect(vl, vr);
	}
};

int main()
{
	int H,W,Q;cin>>H>>W>>Q;
	vector<int>as(H),bs(W);
	for(int i=0;i<H;++i)cin>>as[i];
	for(int i=0;i<W;++i)cin>>bs[i];
	lazy_segtree aseg(H),bseg(W);
	for (int i = 0; i < H; ++i) {
		aseg.update(i,i+1, as[i]);
	}
	for (int i = 0; i < W; ++i) {
		bseg.update(i,i+1, bs[i]);
	}
	while (Q--) {
		int type;cin>>type;
		if (type == 1) {
			int a,b,x;cin>>a>>b>>x;a--;
			aseg.update(a,b,x);
		}
		else if (type == 2) {
			int a,b,x;cin>>a>>b>>x;a--;
			bseg.update(a,b,x);
		}
		else {
			int a,b,c,d;cin>>a>>b>>c>>d;
			a--;c--;
			auto a_aa=aseg.get(a,b);
			auto b_aa=bseg.get(c,d);

			map<long long int,long long int>mp;

			if (a_aa.amin != a_aa.amax) {
				if (b_aa.amin != b_aa.amax) {

					mp[a_aa.amin*b_aa.amin] += a_aa.min_num*b_aa.min_num;
					mp[a_aa.amax*b_aa.amin] += a_aa.max_num*b_aa.min_num;
					mp[a_aa.amin*b_aa.amax] += a_aa.min_num*b_aa.max_num;
					mp[a_aa.amax*b_aa.amax] += a_aa.max_num*b_aa.max_num;
				}
				else {

					mp[a_aa.amin*b_aa.amin] += a_aa.min_num*b_aa.min_num;
					mp[a_aa.amax*b_aa.amin] += a_aa.max_num*b_aa.min_num;
				}
			}
			else {
				if (b_aa.amin != b_aa.amax) {

					mp[a_aa.amin*b_aa.amin] += a_aa.min_num*b_aa.min_num;
					mp[a_aa.amin*b_aa.amax] += a_aa.min_num*b_aa.max_num;
				}
				else {
					mp[a_aa.amin*b_aa.amin] += a_aa.min_num*b_aa.min_num;
				}
			}

			auto it=mp.begin();
			auto jt=prev(mp.end());

			if (type == 3) {
				long long int ans_num,ans_cnt;
				if (it->first == 0) {
					if (a_aa.amin == 0 && b_aa.amin == 0) {
						ans_cnt = (b - a)*b_aa.min_num + (d - c)*a_aa.min_num - a_aa.min_num*b_aa.min_num;
					}
					else if (a_aa.amin == 0) {
						ans_cnt=(d-c)*a_aa.min_num;
					}
					else if(b_aa.amin==0){
						ans_cnt=(b-a)*b_aa.min_num;
					}
					else {
						swap(a_aa.amin,a_aa.amax);
						swap(a_aa.min_num,a_aa.max_num);
						swap(b_aa.amin,b_aa.amax);
						swap(b_aa.min_num, b_aa.max_num);

						if (a_aa.amin == 0 && b_aa.amin == 0) {
							ans_cnt = (b - a)*b_aa.min_num + (d - c)*a_aa.min_num - a_aa.min_num*b_aa.min_num;
						}
						else if (a_aa.amin == 0) {
							ans_cnt = (d - c)*a_aa.min_num;
						}
						else if (b_aa.amin == 0) {
							ans_cnt = (b - a)*b_aa.min_num;
						}
						else {
							assert(false);
						}
					}
				}
				else {
					ans_cnt=it->second;
				}
				cout<<it->first<<" "<<ans_cnt<<endl;
			}
			else {
				long long int ans_num, ans_cnt;
				swap(b_aa.amin,b_aa.amax);
				swap(b_aa.min_num,b_aa.max_num);
				if (jt->first == 0) {
					if (a_aa.amin == 0 && b_aa.amin == 0) {
						ans_cnt = (b - a)*b_aa.min_num + (d - c)*a_aa.min_num - a_aa.min_num*b_aa.min_num;
					}
					else if (a_aa.amin == 0) {
						ans_cnt = (d - c)*a_aa.min_num;
					}
					else if (b_aa.amin == 0) {
						ans_cnt = (b - a)*b_aa.min_num;
					}
					else {
						swap(a_aa.amin, a_aa.amax);
						swap(a_aa.min_num, a_aa.max_num);
						swap(b_aa.amin, b_aa.amax);
						swap(b_aa.min_num, b_aa.max_num);

						if (a_aa.amin == 0 && b_aa.amin == 0) {
							ans_cnt = (b - a)*b_aa.min_num + (d - c)*a_aa.min_num - a_aa.min_num*b_aa.min_num;
						}
						else if (a_aa.amin == 0) {
							ans_cnt = (d - c)*a_aa.min_num;
						}
						else if (b_aa.amin == 0) {
							ans_cnt = (b - a)*b_aa.min_num;
						}
						else {
							assert(false);
						}
					}
				}
				else {
					ans_cnt = jt->second;
				}
				cout << jt->first << " " << ans_cnt << endl;
			}
		}
	}
	return 0;
}

```