// clang-format off
// very important, much wow, such don't touch this
#define protected public
using iii = int; using yeee = iii;

#ifdef LOCAL
    const iii DEBUG = 0;
#else
    const iii DEBUG = -1;
#endif
#define DBG(x) if(DEBUG >= x)

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

#if 0
    #include <ext/pb_ds/assoc_container.hpp>
    #include <ext/pb_ds/detail/standard_policies.hpp>
    using namespace __gnu_pbds;
    template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
    template<class T, class U> using hash_map = gp_hash_table<T, U>;
#endif

#define FOR(i, lo, hi) for(ll i = ll(lo); i < ll(hi); ++i)
#define ROF(i, hi, lo) for(ll i = ll(hi); i >= (ll)(lo); --i)
#define all(x) (x).begin(), (x).end()
#define len(x) ll((x).size())
#define pb push_back
#define apply(f, x, y) (x) = f((x), (y))

using ll = int; using ull = unsigned long long; using ld = long double; using pll = pair<ll, ll>; using vb = vector<bool>; using vvb = vector<vb>; using vll = vector<ll>; using vvll = vector<vll>; using vpll = vector<pll>; using point = complex<ll>; /*|||*/ template <class T> T get() { T x; cin >> x; return x; } template <class T1, class T2> ostream &operator<<(ostream &out, const pair<T1, T2> &cont) { out << "(" << cont.first << ", " << cont.second << ")"; return out; } template <class T> ostream &operator<<(ostream &out, const vector<T> &cont) { for(long long int i=0; i < (long long int)(cont.size()); ++i) out << (i ? " " : "") << cont[i]; return out; } template <class T> ostream &operator<<(ostream &out, const set<T> &cont) { out << "{"; for(const T &x : cont) out << x << ", "; out << "}"; return out; } template <class T, class U> ostream &operator<<(ostream &out, const map<T, U> &cont) { out << "{"; for(const pair<T, U> &x : cont) out << "(" << x.first << ": " << x.second << "), "; out << "}"; return out; } template <class T> ostream &operator<<(ostream &out, vector<vector<T>> &cont) { for(vector<T> &v : cont) { for(long long int i = 0; i < (long long int)(v.size()); ++i) { out << (i ? " " : "") << v[i]; } out << "\n"; } return out; } /*|||*/ void setup_io(string input_file = "", string output_file = "", bool fast_cio = true) { if(fast_cio) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); } srand(unsigned(time(0))); DBG(0 && input_file != "") freopen(input_file.c_str(), "r", stdin); DBG(0 && output_file != "") freopen(output_file.c_str(), "w", stdout); } /*|||*/ std::chrono::_V2::system_clock::time_point get_time() { return chrono::high_resolution_clock::now(); } ld get_duration(std::chrono::_V2::system_clock::time_point start_time, std::chrono::_V2::system_clock::time_point end_time) { return ld(chrono::duration_cast<chrono::nanoseconds>(end_time - start_time).count()) / 1e9; } /*|||*/ ll sign(ld x) { return (x > 0) - (x < 0); } ll pow(ll x, ll exp, ll mod) { ll res = 1, y = x; while(exp) { if(!mod) { if(exp & 1) res = res * y; y = y * y; } else { if(exp & 1) res = (res * y) % mod; y = (y * y) % mod; } exp >>= 1; } return res; } /*|||*/ auto START_TIME = get_time(); const long long INF = LONG_LONG_MAX / 3; char newl = '\n';
// clang-format on

yeee main() {
    setup_io();
    //

    ll R, C;
    cin >> R >> C;

    ll B[1005][1005] = {};
    FOR(y, 0, R)
        FOR(x, 0, C)
            cin >> B[y][x];

    ll D[4][1005][1005] = {};

    FOR(y, 1, R + 1)
        FOR(x, 1, C + 1)
            D[0][y][x] = B[y - 1][x - 1] + max(D[0][y - 1][x], D[0][y][x - 1]);
    ROF(y, R, 1)
        FOR(x, 1, C + 1)
            D[1][y][x] = B[y - 1][x - 1] + max(D[1][y + 1][x], D[1][y][x - 1]);
    ROF(y, R, 1)
        ROF(x, C, 1)
            D[2][y][x] = B[y - 1][x - 1] + max(D[2][y + 1][x], D[2][y][x + 1]);
    FOR(y, 1, R + 1)
        ROF(x, C, 1)
            D[3][y][x] = B[y - 1][x - 1] + max(D[3][y - 1][x], D[3][y][x + 1]);

    DBG(1)
    FOR(i, 0, 4) {
        cout << D[i] << endl;
        cout << "---" << endl;
    }

    ll res = 0;
    FOR(y, 2, R) {
        FOR(x, 2, C) {
            apply(max,
                  res,
                  D[0][y - 1][x] + D[2][y + 1][x] + D[1][y][x - 1] +
                      D[3][y][x + 1]);
            apply(max,
                  res,
                  D[0][y][x - 1] + D[2][y][x + 1] + D[1][y + 1][x] +
                      D[3][y - 1][x]);
            DBG(3) cout << vll{y, x, res} << endl;
        }
    }

    cout << res << endl;
}


#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
using vi  = vector<int>;
using ii  = pair<int,int>;
using vii = vector<ii>;
using ll  = long long;

typedef tree<int, null_type, less<int>, rb_tree_tag,
tree_order_statistics_node_update> ordered_set;

#define F first
#define S second
#define PB push_back
#define EB emplace_back
#define ALL(x) (x).begin(), (x).end()
#define SIZE(x) int((x).size())
#define REP(i, a, b) for (auto (i) = (a); (i) <= (b); (i)++)
#define PER(i, a, b) for (auto (i) = (a); (i) >= (b); (i)--)
#define ITR(i, x) for (auto (i) = (x).begin(); (i) != (x).end(); (i)++)

const int N = 1e3;
int a[N+5][N+5], nw[N+5][N+5], ne[N+5][N+5], sw[N+5][N+5], se[N+5][N+5];

signed main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);

	int r, c;
	cin >> r >> c;
	REP(i, 0, r-1) REP(j, 0, c-1) {
		cin >> a[i][j];
	}
	REP(i, 0, r-1) REP(j, 0, c-1) {
		nw[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, nw[i-1][j]);
		if (j > 0) add = max(add, nw[i][j-1]);
		nw[i][j] += add;
	}
	REP(i, 0, r-1) PER(j, c-1, 0) {
		ne[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, ne[i-1][j]);
		if (j < c-1) add = max(add, ne[i][j+1]);
		ne[i][j] += add;
	}
	PER(i, r-1, 0) REP(j, 0, c-1) {
		sw[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, sw[i+1][j]);
		if (j > 0) add = max(add, sw[i][j-1]);
		sw[i][j] += add;
	}
	PER(i, r-1, 0) REP(j, 0, c-1) {
		se[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, se[i+1][j]);
		if (j < c-1) add = max(add, se[i][j+1]);
		se[i][j] += add;
	}

	int best = 0;
	REP(i, 0, r-1) REP(j, 0, c-1) {
		int curr = 0;
		curr += nw[i][j] - a[i][j];
		curr += ne[i][j] - a[i][j];
		curr += sw[i][j] - a[i][j];
		curr += se[i][j] - a[i][j];
		best = max(best, curr);
	}

	cout << best << '\n';
	return 0;
}


#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
using vi  = vector<int>;
using ii  = pair<int,int>;
using vii = vector<ii>;
using ll  = long long;

typedef tree<int, null_type, less<int>, rb_tree_tag,
tree_order_statistics_node_update> ordered_set;

#define F first
#define S second
#define PB push_back
#define EB emplace_back
#define ALL(x) (x).begin(), (x).end()
#define SIZE(x) int((x).size())
#define REP(i, a, b) for (auto (i) = (a); (i) <= (b); (i)++)
#define PER(i, a, b) for (auto (i) = (a); (i) >= (b); (i)--)
#define ITR(i, x) for (auto (i) = (x).begin(); (i) != (x).end(); (i)++)

const int N = 1e3;
int a[N+5][N+5], nw[N+5][N+5], ne[N+5][N+5], sw[N+5][N+5], se[N+5][N+5];

signed main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);

	int r, c;
	cin >> r >> c;
	REP(i, 0, r-1) REP(j, 0, c-1) {
		cin >> a[i][j];
	}
	REP(i, 0, r-1) REP(j, 0, c-1) {
		nw[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, nw[i-1][j]);
		if (j > 0) add = max(add, nw[i][j-1]);
		nw[i][j] += add;
	}
	REP(i, 0, r-1) PER(j, c-1, 0) {
		ne[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, ne[i-1][j]);
		if (j < c-1) add = max(add, ne[i][j+1]);
		ne[i][j] += add;
	}
	PER(i, r-1, 0) REP(j, 0, c-1) {
		sw[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, sw[i+1][j]);
		if (j > 0) add = max(add, sw[i][j-1]);
		sw[i][j] += add;
	}
	PER(i, r-1, 0) PER(j, c-1, 0) {
		se[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, se[i+1][j]);
		if (j < c-1) add = max(add, se[i][j+1]);
		se[i][j] += add;
	}
	// cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << nw[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << ne[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << sw[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << se[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	int best = 0;
	REP(i, 1, r-2) REP(j, 1, c-2) {
		int best1 = nw[i-1][j] + se[i+1][j] + ne[i][j+1] + sw[i][j-1];
		int best2 = nw[i][j-1] + se[i][j+1] + ne[i-1][j] + sw[i+1][j];
		best = max(best, best1);
		best = max(best, best2);
	}

	cout << best << '\n';
	return 0;
}


#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
using vi  = vector<int>;
using ii  = pair<int,int>;
using vii = vector<ii>;
using ll  = long long;

typedef tree<int, null_type, less<int>, rb_tree_tag,
tree_order_statistics_node_update> ordered_set;

#define F first
#define S second
#define PB push_back
#define EB emplace_back
#define ALL(x) (x).begin(), (x).end()
#define SIZE(x) int((x).size())
#define REP(i, a, b) for (auto (i) = (a); (i) <= (b); (i)++)
#define PER(i, a, b) for (auto (i) = (a); (i) >= (b); (i)--)
#define ITR(i, x) for (auto (i) = (x).begin(); (i) != (x).end(); (i)++)

const int N = 1e3;
int a[N+5][N+5], nw[N+5][N+5], ne[N+5][N+5], sw[N+5][N+5], se[N+5][N+5];

signed main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);

	int r, c;
	cin >> r >> c;
	REP(i, 0, r-1) REP(j, 0, c-1) {
		cin >> a[i][j];
	}
	REP(i, 0, r-1) REP(j, 0, c-1) {
		nw[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, nw[i-1][j]);
		if (j > 0) add = max(add, nw[i][j-1]);
		nw[i][j] += add;
	}
	REP(i, 0, r-1) PER(j, c-1, 0) {
		ne[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, ne[i-1][j]);
		if (j < c-1) add = max(add, ne[i][j+1]);
		ne[i][j] += add;
	}
	PER(i, r-1, 0) REP(j, 0, c-1) {
		sw[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, sw[i+1][j]);
		if (j > 0) add = max(add, sw[i][j-1]);
		sw[i][j] += add;
	}
	PER(i, r-1, 0) PER(j, c-1, 0) {
		se[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, se[i+1][j]);
		if (j < c-1) add = max(add, se[i][j+1]);
		se[i][j] += add;
	}
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << nw[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << ne[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << sw[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << se[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	int best = 0;
	REP(i, 0, r-1) REP(j, 0, c-1) {
		if ((i == 0 or i == r-1) and (j == 0 or j == c-1)) continue;
		int curr = 0;
		curr += nw[i][j] - a[i][j];
		curr += ne[i][j] - a[i][j];
		curr += sw[i][j] - a[i][j];
		curr += se[i][j] - a[i][j];
		best = max(best, curr);
	}

	cout << best << '\n';
	return 0;
}


#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
using vi  = vector<int>;
using ii  = pair<int,int>;
using vii = vector<ii>;
using ll  = long long;

typedef tree<int, null_type, less<int>, rb_tree_tag,
tree_order_statistics_node_update> ordered_set;

#define F first
#define S second
#define PB push_back
#define EB emplace_back
#define ALL(x) (x).begin(), (x).end()
#define SIZE(x) int((x).size())
#define REP(i, a, b) for (auto (i) = (a); (i) <= (b); (i)++)
#define PER(i, a, b) for (auto (i) = (a); (i) >= (b); (i)--)
#define ITR(i, x) for (auto (i) = (x).begin(); (i) != (x).end(); (i)++)

const int N = 1e3;
int a[N+5][N+5], nw[N+5][N+5], ne[N+5][N+5], sw[N+5][N+5], se[N+5][N+5];

signed main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);

	int r, c;
	cin >> r >> c;
	REP(i, 0, r-1) REP(j, 0, c-1) {
		cin >> a[i][j];
	}
	REP(i, 0, r-1) REP(j, 0, c-1) {
		nw[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, nw[i-1][j]);
		if (j > 0) add = max(add, nw[i][j-1]);
		nw[i][j] += add;
	}
	REP(i, 0, r-1) PER(j, c-1, 0) {
		ne[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, ne[i-1][j]);
		if (j < c-1) add = max(add, ne[i][j+1]);
		ne[i][j] += add;
	}
	PER(i, r-1, 0) REP(j, 0, c-1) {
		sw[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, sw[i+1][j]);
		if (j > 0) add = max(add, sw[i][j-1]);
		sw[i][j] += add;
	}
	PER(i, r-1, 0) PER(j, c-1, 0) {
		se[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, se[i+1][j]);
		if (j < c-1) add = max(add, se[i][j+1]);
		se[i][j] += add;
	}
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << nw[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << ne[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << sw[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << se[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	int best = 0;
	REP(i, 0, r-1) REP(j, 0, c-1) {
		int curr = 0;
		curr += nw[i][j] - a[i][j];
		curr += ne[i][j] - a[i][j];
		curr += sw[i][j] - a[i][j];
		curr += se[i][j] - a[i][j];
		best = max(best, curr);
	}

	cout << best << '\n';
	return 0;
}


#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
using vi  = vector<int>;
using ii  = pair<int,int>;
using vii = vector<ii>;
using ll  = long long;

typedef tree<int, null_type, less<int>, rb_tree_tag,
tree_order_statistics_node_update> ordered_set;

#define F first
#define S second
#define PB push_back
#define EB emplace_back
#define ALL(x) (x).begin(), (x).end()
#define SIZE(x) int((x).size())
#define REP(i, a, b) for (auto (i) = (a); (i) <= (b); (i)++)
#define PER(i, a, b) for (auto (i) = (a); (i) >= (b); (i)--)
#define ITR(i, x) for (auto (i) = (x).begin(); (i) != (x).end(); (i)++)

const int N = 1e3;
int a[N+5][N+5], nw[N+5][N+5], ne[N+5][N+5], sw[N+5][N+5], se[N+5][N+5];

signed main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);

	int r, c;
	cin >> r >> c;
	REP(i, 0, r-1) REP(j, 0, c-1) {
		cin >> a[i][j];
	}
	REP(i, 0, r-1) REP(j, 0, c-1) {
		nw[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, nw[i-1][j]);
		if (j > 0) add = max(add, nw[i][j-1]);
		nw[i][j] += add;
	}
	REP(i, 0, r-1) PER(j, c-1, 0) {
		ne[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, ne[i-1][j]);
		if (j < c-1) add = max(add, ne[i][j+1]);
		ne[i][j] += add;
	}
	PER(i, r-1, 0) REP(j, 0, c-1) {
		sw[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, sw[i+1][j]);
		if (j > 0) add = max(add, sw[i][j-1]);
		sw[i][j] += add;
	}
	PER(i, r-1, 0) REP(j, 0, c-1) {
		se[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, se[i+1][j]);
		if (j < c-1) add = max(add, se[i][j+1]);
		se[i][j] += add;
	}

	int best = 0;
	REP(i, 1, r-2) REP(j, 1, c-2) {
		int curr = 0;
		curr += nw[i][j] - a[i][j];
		curr += ne[i][j] - a[i][j];
		curr += sw[i][j] - a[i][j];
		curr += se[i][j] - a[i][j];
		best = max(best, curr);
	}

	cout << best << '\n';
	return 0;
}


#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
using vi  = vector<int>;
using ii  = pair<int,int>;
using vii = vector<ii>;
using ll  = long long;

typedef tree<int, null_type, less<int>, rb_tree_tag,
tree_order_statistics_node_update> ordered_set;

#define F first
#define S second
#define PB push_back
#define EB emplace_back
#define ALL(x) (x).begin(), (x).end()
#define SIZE(x) int((x).size())
#define REP(i, a, b) for (auto (i) = (a); (i) <= (b); (i)++)
#define PER(i, a, b) for (auto (i) = (a); (i) >= (b); (i)--)
#define ITR(i, x) for (auto (i) = (x).begin(); (i) != (x).end(); (i)++)

const int N = 1e3;
int a[N+5][N+5], nw[N+5][N+5], ne[N+5][N+5], sw[N+5][N+5], se[N+5][N+5];

signed main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);

	int r, c;
	cin >> r >> c;
	REP(i, 0, r-1) REP(j, 0, c-1) {
		cin >> a[i][j];
	}
	REP(i, 0, r-1) REP(j, 0, c-1) {
		nw[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, nw[i-1][j]);
		if (j > 0) add = max(add, nw[i][j-1]);
		nw[i][j] += add;
	}
	REP(i, 0, r-1) PER(j, c-1, 0) {
		ne[i][j] = a[i][j];
		int add = 0;
		if (i > 0) add = max(add, ne[i-1][j]);
		if (j < c-1) add = max(add, ne[i][j+1]);
		ne[i][j] += add;
	}
	PER(i, r-1, 0) REP(j, 0, c-1) {
		sw[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, sw[i+1][j]);
		if (j > 0) add = max(add, sw[i][j-1]);
		sw[i][j] += add;
	}
	PER(i, r-1, 0) PER(j, c-1, 0) {
		se[i][j] = a[i][j];
		int add = 0;
		if (i < r-1) add = max(add, se[i+1][j]);
		if (j < c-1) add = max(add, se[i][j+1]);
		se[i][j] += add;
	}
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << nw[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << ne[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << sw[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	// REP(i, 0, r-1) REP(j, 0, c-1) {
	// 	cout << se[i][j] << " \n"[j == c-1];
	// } cout << '\n';
	int best = 0;
	REP(i, 1, r-2) REP(j, 1, c-2) {
		int curr = 0;
		curr += nw[i][j] - a[i][j];
		curr += ne[i][j] - a[i][j];
		curr += sw[i][j] - a[i][j];
		curr += se[i][j] - a[i][j];
		best = max(best, curr);
	}

	cout << best << '\n';
	return 0;
}


/*

   CODEFORCES 429B
   WORKING OUT

*/

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

#define fastIO    ios::sync_with_stdio(0), cin.tie(0)
#define debug(x)  cout << "[ " << #x << " = " << x << " ]\n"

#define forn(i,n) for( __typeof(n) i=0 ; i<n ; ++i )
#define all(v) v.begin(),v.end()
#define rall(v) v.rbegin(),v.rend()
#define pb push_back

const Long INF = 1e18 + 10 ;
const int SZ = 1000 + 5 ;

Long grid[SZ][SZ];
int n , m ;
Long dp1[SZ][SZ] , dp2[SZ][SZ] , dp3[SZ][SZ] , dp4[SZ][SZ];

int main(){

   fastIO;

   cin >> n >> m;

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = 1 ; j <= m ; ++j ){
         cin >> grid[i][j];
      }
   }

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = 1 ; j <= m ; ++j ){
         dp1[i][j] = grid[i][j] + max( dp1[i][j-1] , dp1[i-1][j] );
      }
   }

   for( int i = n ; i >= 1 ; --i ){
      for( int j = m ; j >= 1 ; --j ){
         dp2[i][j] = grid[i][j] + max( dp2[i][j+1] , dp2[i+1][j] );
      }
   }

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = m ; j >= 1 ; --j ){
         dp3[i][j] = grid[i][j] + max( dp3[i-1][j] , dp3[i][j+1] );
      }
   }

   for( int i = n ; i >= 1 ; --i ){
      for( int j = 1 ; j <= m ; ++j ){
         dp4[i][j] = grid[i][j] + max( dp4[i][j-1] , dp4[i+1][j] );
      }
   }

   Long ans = 0;

   for( int i = 2 ; i <= n - 1 ; ++i ){
      for( int j = 2 ; j <= m - 1 ; ++j ){
         ans = max ( dp1[i-1][j] + dp2[i+1][j] + dp3[i][j+1] + dp4[i][j-1] ,
                     dp1[i][j-1] + dp2[i][j+1] + dp3[i-1][j] + dp4[i+1][j] );
      }
   }
   cout << ans << endl;
   return 0;
}


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

#define fastIO    ios::sync_with_stdio(0), cin.tie(0)
#define debug(x)  cout << "[ " << #x << " = " << x << " ]\n"

#define forn(i,n) for( __typeof(n) i=0 ; i<n ; ++i )
#define all(v) v.begin(),v.end()
#define rall(v) v.rbegin(),v.rend()
#define pb push_back

const Long INF = 1e18 + 10 ;
const int SZ = 1000 + 5 ;

Long grid[SZ][SZ];
int n , m ;
Long dp1[SZ][SZ] , dp2[SZ][SZ] , dp3[SZ][SZ] , dp4[SZ][SZ];

int main(){

   fastIO;

   cin >> n >> m;

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = 1 ; j <= m ; ++j ){
         cin >> grid[i][j];
      }
   }

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = 1 ; j <= m ; ++j ){
         dp1[i][j] = grid[i][j] + max( dp1[i][j-1] , dp1[i-1][j] );
      }
   }

   for( int i = n ; i >= 1 ; --i ){
      for( int j = m ; j >= 1 ; --j ){
         dp2[i][j] = grid[i][j] + max( dp2[i][j+1] , dp2[i+1][j] );
      }
   }

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = m ; j >= 1 ; --j ){
         dp3[i][j] = grid[i][j] + max( dp3[i-1][j] , dp3[i][j+1] );
      }
   }

   for( int i = n ; i >= 1 ; --i ){
      for( int j = 1 ; j <= m ; ++j ){
         dp4[i][j] = grid[i][j] + max( dp4[i][j-1] , dp4[i+1][j] );
      }
   }

   Long ans = 0;

   for( int i = 2 ; i <= n - 1 ; ++i ){
      for( int j = 2 ; j <= m - 1 ; ++j ){
         ans = max ( dp1[i-1][j] + dp2[i+1][j] + dp3[i][j+1] + dp4[i][j-1] ,
                     dp1[i][j-1] + dp2[i][j+1] + dp3[i-1][j] + dp4[i+1][j] );
      }
   }
   cout << ans << endl;
   return 0;
}


/*

   CODEFORCES 429B
   WORKING OUT

*/

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

#define fastIO    ios::sync_with_stdio(0), cin.tie(0)
#define debug(x)  cout << "[ " << #x << " = " << x << " ]\n"

#define forn(i,n) for( __typeof(n) i=0 ; i<n ; ++i )
#define all(v) v.begin(),v.end()
#define rall(v) v.rbegin(),v.rend()
#define pb push_back

const Long INF = 1e18 + 10 ;
const int SZ = 100 + 5 ;

int grid[SZ][SZ];
int n , m ;
int dp1[SZ][SZ] , dp2[SZ][SZ] , dp3[SZ][SZ] , dp4[SZ][SZ];

int main(){

   fastIO;

   cin >> n >> m;

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = 1 ; j <= m ; ++j ){
         cin >> grid[i][j];
      }
   }

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = 1 ; j <= m ; ++j ){
         dp1[i][j] = grid[i][j] + max( dp1[i][j-1] , dp1[i-1][j] );
      }
   }

   for( int i = n ; i >= 1 ; --i ){
      for( int j = m ; j >= 1 ; --j ){
         dp2[i][j] = grid[i][j] + max( dp2[i][j+1] , dp2[i+1][j] );
      }
   }

   for( int i = n ; i >= 1 ; --i ){
      for( int j = 1 ; j <= m ; ++j ){
         dp3[i][j] = grid[i][j] + max( dp3[i][j-1] , dp3[i+1][j] );
      }
   }

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = m ; j >= 1 ; --j ){
         dp4[i][j] = grid[i][j] + max( dp4[i-1][j] , dp4[i][j+1] );
      }
   }

   int ans = -1;

   for( int i = 2 ; i <= n - 1 ; ++i ){
      for( int j = 2 ; j <= m - 1 ; ++j ){
         ans = max ( dp1[i-1][j] + dp2[i+1][j] + dp3[i][j-1] + dp4[i][j+1] ,
                     dp1[i][j-1] + dp2[i][j+1] + dp3[i+1][j] + dp4[i-1][j] );
      }
   }
   cout << ans << endl;
   return 0;
}


/*

   CODEFORCES 429B
   WORKING OUT

*/

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

#define fastIO    ios::sync_with_stdio(0), cin.tie(0)
#define debug(x)  cout << "[ " << #x << " = " << x << " ]\n"

#define forn(i,n) for( __typeof(n) i=0 ; i<n ; ++i )
#define all(v) v.begin(),v.end()
#define rall(v) v.rbegin(),v.rend()
#define pb push_back

const Long INF = 1e18 + 10 ;
const int SZ = 100 + 5 ;

int grid[SZ][SZ];
int n , m ;
int dp1[SZ][SZ] , dp2[SZ][SZ] , dp3[SZ][SZ] , dp4[SZ][SZ];

int main(){

   fastIO;

   cin >> n >> m;

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = 1 ; j <= m ; ++j ){
         cin >> grid[i][j];
      }
   }

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = 1 ; j <= m ; ++j ){
         dp1[i][j] = grid[i][j] + max( dp1[i][j-1] , dp1[i-1][j] );
      }
   }

   for( int i = n ; i >= 1 ; --i ){
      for( int j = m ; j >= 1 ; --j ){
         dp2[i][j] = grid[i][j] + max( dp2[i][j+1] , dp2[i+1][j] );
      }
   }

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = m ; j >= 1 ; --j ){
         dp3[i][j] = grid[i][j] + max( dp3[i-1][j] , dp3[i][j+1] );
      }
   }

   for( int i = n ; i >= 1 ; --i ){
      for( int j = 1 ; j <= m ; ++j ){
         dp4[i][j] = grid[i][j] + max( dp4[i][j-1] , dp4[i+1][j] );
      }
   }

   int ans = -1;

   for( int i = 2 ; i <= n - 1 ; ++i ){
      for( int j = 2 ; j <= m - 1 ; ++j ){
         ans = max ( dp1[i-1][j] + dp2[i+1][j] + dp3[i][j+1] + dp4[i][j-1] ,
                     dp1[i][j-1] + dp2[i][j+1] + dp3[i-1][j] + dp4[i+1][j] );
      }
   }
   cout << ans << endl;
   return 0;
}


/*

   CODEFORCES 429B
   WORKING OUT

*/

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

#define fastIO    ios::sync_with_stdio(0), cin.tie(0)
#define debug(x)  cout << "[ " << #x << " = " << x << " ]\n"

#define forn(i,n) for( __typeof(n) i=0 ; i<n ; ++i )
#define all(v) v.begin(),v.end()
#define rall(v) v.rbegin(),v.rend()
#define pb push_back

const Long INF = 1e18 + 10 ;
const int SZ = 100 + 5 ;

int grid[SZ][SZ];
int n , m ;
int dp1[SZ][SZ] , dp2[SZ][SZ] , dp3[SZ][SZ] , dp4[SZ][SZ];

int main(){

   fastIO;

   cin >> n >> m;

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = 1 ; j <= m ; ++j ){
         cin >> grid[i][j];
      }
   }

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = 1 ; j <= m ; ++j ){
         dp1[i][j] = grid[i][j] + max( dp1[i][j-1] , dp1[i-1][j] );
      }
   }

   for( int i = n ; i >= 1 ; --i ){
      for( int j = m ; j >= 1 ; --j ){
         dp2[i][j] = grid[i][j] + max( dp2[i][j+1] , dp2[i+1][j] );
      }
   }

   for( int i = n ; i >= 1 ; --i ){
      for( int j = 1 ; j <= m ; ++j ){
         dp3[i][j] = grid[i][j] + max( dp3[i][j-1] , dp3[i+1][j] );
      }
   }

   for( int i = 1 ; i <= n ; ++i ){
      for( int j = m ; j >= 1 ; --j ){
         dp4[i][j] = grid[i][j] + max( dp4[i-1][j] , dp4[i][j+1] );
      }
   }

   int ans = 2e9 + 10;

   for( int i = 2 ; i <= n - 1 ; ++i ){
      for( int j = 2 ; j <= m - 1 ; ++j ){
         ans = min ( dp1[i-1][j] + dp2[i+1][j] + dp3[i][j-1] + dp4[i][j+1] ,
                     dp1[i][j-1] + dp2[i][j+1] + dp3[i+1][j] + dp4[i-1][j] );
      }
   }
   cout << ans << endl;
   return 0;
}


/*

   CODEFORCES 429B
   WORKING OUT

*/

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

#define fastIO    ios::sync_with_stdio(0), cin.tie(0)
#define debug(x)  cout << "[ " << #x << " = " << x << " ]\n"

#define forn(i,n) for( __typeof(n) i=0 ; i<n ; ++i )
#define all(v) v.begin(),v.end()
#define rall(v) v.rbegin(),v.rend()
#define pb push_back

const Long INF = 1e18 + 10 ;
const int SZ = 1000 + 5 ;

Long grid[SZ][SZ];
int n , m ;
Long dp1[SZ][SZ] , dp2[SZ][SZ] , dp3[SZ][SZ] , dp4[SZ][SZ];

int main(){

   fastIO;

   cin >> n >> m;

   for( int i = 1 ; i <= n ; i++ ){
      for( int j = 1 ; j <= m ; j++ ){
         cin >> grid[i][j];
      }
   }

   // max cost 1,1 -> i,j

   for( int i = 1 ; i <= n ; i++ ){
      for( int j = 1 ; j <= m ; j++ ){
         dp1[i][j] = grid[i][j] + max( dp1[i][j-1] , dp1[i-1][j] );
      }
   }

   // max cost i,j -> n,m

   for( int i = n ; i >= 1 ; i-- ){
      for( int j = m ; j >= 1 ; j--){
         dp2[i][j] = grid[i][j] + max( dp2[i][j+1] , dp2[i+1][j] );
      }
   }

   // max cost n,1 -> i,j

   for( int i = n ; i >= 1 ; i-- ){
      for( int j = 1 ; j <= m ; j++ ){
         dp3[i][j] = grid[i][j] + max( dp3[i][j-1] , dp3[i+1][j] );
      }
   }

   // max cost i,j -> 1,m

   for( int i = 1 ; i <= n ; i++ ){
      for( int j = m ; j >= 1 ; j--){
         dp4[i][j] = grid[i][j] + max( dp4[i][j+1] , dp4[i-1][j] );
      }
   }

   Long ans = 0;
   for( int i = 2 ; i < n ; i++ ){
      for( int j = 2 ; j < m ; j++ ){
         //            | 4
         //      1 --> c ---> 2
         //            | 3
         ans = max ( ans , dp1[i][j-1] + dp2[i][j+1] + dp3[i+1][j] + dp4[i-1][j] );
         //            | 1
         //      3 --> c ---> 4
         //            | 2
         ans = max ( ans , dp1[i-1][j] + dp2[i+1][j] + dp3[i][j-1] + dp4[i][j+1] );
      }
   }
   cout << ans ;
   return 0;
}


// Problem : B. Working out
// Contest : Codeforces - Codeforces Round #245 (Div. 1)
// URL : https://codeforces.com/contest/429/problem/B
// Memory Limit : 256 MB
// Time Limit : 2000 ms
// Powered by CP Editor (https://github.com/cpeditor/cpeditor)

/*ヽ｀、ヽ｀｀、ヽ｀ヽ｀、、ヽ ｀ヽ 、ヽ｀🌙｀ヽヽ｀ヽ、ヽ｀
ヽ｀、ヽ｀｀、ヽ 、｀｀、 ｀、ヽ｀ 、｀ ヽ｀ヽ、ヽ ｀、ヽ｀｀、
ヽ、｀｀、｀、ヽ｀｀、 、ヽヽ｀、｀、、ヽヽ、｀｀、 、 ヽ｀、
ヽ｀｀、 ヽ｀ヽ｀、、ヽ ｀ヽ 、 🚶ヽ｀｀｀｀ヽヽヽ｀、、ヽ｀、、ヽ*/

// #pragma GCC optimize ("O3")
// #pragma GCC target ("sse4")

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,b,a) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
#define trav(a,x) for (auto& a : x)

#define bug(x) cout<<#x<<"="<<x<<endl;
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()
#define ins insert

template<class T> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const ld pii=3.14159265359;
const int MOD = 1000000007;
const char nl = '\n';
const int MX = 200001; //check the limits, dummy

int main()
{
	//binary search lag skta kya?
	ios_base::sync_with_stdio(0); cin.tie(0);
	int N,M;cin>>N>>M;
	vector<vi> v(N,vi(M));
	trav(i,v)
		trav(j,i)
			cin>>j;
	ll dp[4][N][M];
	F0R(x,N)F0R(y,M)F0R(z,4)dp[z][x][y]=0;

	int p=0;
	F0R(x,N)
	{
		F0R(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=0)
			{
				dp[p][x][y]+=dp[p][x-1][y];
			}
			if(y!=0)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y-1]);
			}
		}
	}
	p++;
	F0R(x,N)
	{
		F0Rd(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=0)
			{
				dp[p][x][y]+=dp[p][x-1][y];
			}
			if(y!=M-1)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y+1]);
			}
		}
	}
	p++;
	F0Rd(x,N)
	{
		F0Rd(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=N-1)
			{
				dp[p][x][y]+=dp[p][x+1][y];
			}
			if(y!=M-1)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y+1]);
			}
		}
	}
	p++;
	F0Rd(x,N)
	{
		F0R(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=N-1)
			{
				dp[p][x][y]+=dp[p][x+1][y];
			}
			if(y!=0)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y-1]);
			}
		}
	}
	ll ans=LLONG_MIN;
	F0R(x,N)
	{
		F0R(y,M)
		{
			ll r1,r2,r3,r4;
			r1=r2=r3=r4=0;
			if(x!=0)
			{
				r1=dp[0][x-1][y];
				r2=dp[1][x-1][y];
			}
			if(y!=0)
			{
				r4=dp[3][x][y-1];
				ckmax(r1,dp[0][x][y-1]);
			}
			if(x!=N-1)
			{
				ckmax(r4,dp[3][x+1][y]);
				ckmax(r3,dp[2][x+1][y]);
			}
			if(y!=M-1)
			{
				// ckmax(r4,dp[3][x][y+1]);
				ckmax(r2,dp[1][x][y+1]);
				ckmax(r3,dp[2][x][y+1]);
			}
			ckmax(ans,r1+r2+r3+r4);
		}
	}
	// trav(i,dp[0])
	// {
		// trav(j,i)
			// cout<<j<<' ';
		// cout<<nl;
	// }

	cout<<ans;
	return 0;
}

// read the question correctly (ll vs int)
// template by bqi343


// Problem : B. Working out
// Contest : Codeforces - Codeforces Round #245 (Div. 1)
// URL : https://codeforces.com/contest/429/problem/B
// Memory Limit : 256 MB
// Time Limit : 2000 ms
// Powered by CP Editor (https://github.com/cpeditor/cpeditor)

/*ヽ｀、ヽ｀｀、ヽ｀ヽ｀、、ヽ ｀ヽ 、ヽ｀🌙｀ヽヽ｀ヽ、ヽ｀
ヽ｀、ヽ｀｀、ヽ 、｀｀、 ｀、ヽ｀ 、｀ ヽ｀ヽ、ヽ ｀、ヽ｀｀、
ヽ、｀｀、｀、ヽ｀｀、 、ヽヽ｀、｀、、ヽヽ、｀｀、 、 ヽ｀、
ヽ｀｀、 ヽ｀ヽ｀、、ヽ ｀ヽ 、 🚶ヽ｀｀｀｀ヽヽヽ｀、、ヽ｀、、ヽ*/

// #pragma GCC optimize ("O3")
// #pragma GCC target ("sse4")

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,b,a) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
#define trav(a,x) for (auto& a : x)

#define bug(x) cout<<#x<<"="<<x<<endl;
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()
#define ins insert

template<class T> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const ld pii=3.14159265359;
const int MOD = 1000000007;
const char nl = '\n';
const int MX = 200001; //check the limits, dummy

int main()
{
	//binary search lag skta kya?
	ios_base::sync_with_stdio(0); cin.tie(0);
	int N,M;cin>>N>>M;
	vector<vi> v(N,vi(M));
	trav(i,v)
		trav(j,i)
			cin>>j;
	ll dp[4][N][M];
	F0R(x,N)F0R(y,M)F0R(z,4)dp[z][x][y]=0;

	int p=0;
	F0R(x,N)
	{
		F0R(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=0)
			{
				dp[p][x][y]+=dp[p][x-1][y];
			}
			if(y!=0)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y-1]);
			}
		}
	}
	p++;
	F0R(x,N)
	{
		F0Rd(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=0)
			{
				dp[p][x][y]+=dp[p][x-1][y];
			}
			if(y!=M-1)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y+1]);
			}
		}
	}
	p++;
	F0Rd(x,N)
	{
		F0Rd(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=N-1)
			{
				dp[p][x][y]+=dp[p][x+1][y];
			}
			if(y!=M-1)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y+1]);
			}
		}
	}
	p++;
	F0Rd(x,N)
	{
		F0R(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=N-1)
			{
				dp[p][x][y]+=dp[p][x+1][y];
			}
			if(y!=0)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y-1]);
			}
		}
	}
	ll ans=LLONG_MIN;
	FOR(x,1,N-1)
	{
		FOR(y,1,M-1)
		{

			// ckmax(ans,dp[0][x-1][y-1]+dp[1][x-1][y+1]+dp[2][x+1][y+1]+dp[3][x+1][y-1]);
			// ckmax(ans,dp[1][x-1][y-1]+dp[2][x-1][y+1]+dp[3][x+1][y+1]+dp[0][x+1][y-1]);
			ckmax(ans,dp[0][x-1][y]+dp[1][x][y+1]+dp[2][x+1][y]+dp[3][x][y-1]);
			ckmax(ans,dp[0][x][y-1]+dp[1][x-1][y]+dp[2][x][y+1]+dp[3][x+1][y]);
		}
	}
	// F0R(x,4)
	// {trav(i,dp[x])
	// {
		// trav(j,i)
			// cout<<j<<' ';
		// cout<<nl;
	// }cout<<nl;}

	cout<<ans;
	return 0;
}

// read the question correctly (ll vs int)
// template by bqi343


// Problem : B. Working out
// Contest : Codeforces - Codeforces Round #245 (Div. 1)
// URL : https://codeforces.com/contest/429/problem/B
// Memory Limit : 256 MB
// Time Limit : 2000 ms
// Powered by CP Editor (https://github.com/cpeditor/cpeditor)

/*ヽ｀、ヽ｀｀、ヽ｀ヽ｀、、ヽ ｀ヽ 、ヽ｀🌙｀ヽヽ｀ヽ、ヽ｀
ヽ｀、ヽ｀｀、ヽ 、｀｀、 ｀、ヽ｀ 、｀ ヽ｀ヽ、ヽ ｀、ヽ｀｀、
ヽ、｀｀、｀、ヽ｀｀、 、ヽヽ｀、｀、、ヽヽ、｀｀、 、 ヽ｀、
ヽ｀｀、 ヽ｀ヽ｀、、ヽ ｀ヽ 、 🚶ヽ｀｀｀｀ヽヽヽ｀、、ヽ｀、、ヽ*/

// #pragma GCC optimize ("O3")
// #pragma GCC target ("sse4")

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,b,a) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
#define trav(a,x) for (auto& a : x)

#define bug(x) cout<<#x<<"="<<x<<endl;
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()
#define ins insert

template<class T> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const ld pii=3.14159265359;
const int MOD = 1000000007;
const char nl = '\n';
const int MX = 200001; //check the limits, dummy

int main()
{
	//binary search lag skta kya?
	ios_base::sync_with_stdio(0); cin.tie(0);
	int N,M;cin>>N>>M;
	vector<vi> v(N,vi(M));
	trav(i,v)
		trav(j,i)
			cin>>j;
	ll dp[4][N][M];
	F0R(x,N)F0R(y,M)F0R(z,4)dp[z][x][y]=0;

	int p=0;
	F0R(x,N)
	{
		F0R(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=0)
			{
				dp[p][x][y]+=dp[p][x-1][y];
			}
			if(y!=0)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y-1]);
			}
		}
	}
	p++;
	F0R(x,N)
	{
		F0Rd(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=0)
			{
				dp[p][x][y]+=dp[p][x-1][y];
			}
			if(y!=M-1)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y+1]);
			}
		}
	}
	p++;
	F0Rd(x,N)
	{
		F0Rd(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=N-1)
			{
				dp[p][x][y]+=dp[p][x+1][y];
			}
			if(y!=M-1)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y+1]);
			}
		}
	}
	p++;
	F0Rd(x,N)
	{
		F0R(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=N-1)
			{
				dp[p][x][y]+=dp[p][x+1][y];
			}
			if(y!=0)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y-1]);
			}
		}
	}
	ll ans=LLONG_MIN;
	FOR(x,1,N-1)
	{
		FOR(y,1,M-1)
		{

			// ckmax(ans,dp[0][x-1][y-1]+dp[1][x-1][y+1]+dp[2][x+1][y+1]+dp[3][x+1][y-1]);
			// ckmax(ans,dp[1][x-1][y-1]+dp[2][x-1][y+1]+dp[3][x+1][y+1]+dp[0][x+1][y-1]);
			ckmax(ans,dp[0][x][y-1]+dp[1][x-1][y]+dp[2][x+1][y]+dp[3][x][y-1]);
			ckmax(ans,dp[0][x-1][y]+dp[1][x][y+1]+dp[2][x][y+1]+dp[3][x+1][y]);
		}
	}
	// F0R(x,4)
	// {trav(i,dp[x])
	// {
		// trav(j,i)
			// cout<<j<<' ';
		// cout<<nl;
	// }cout<<nl;}

	cout<<ans;
	return 0;
}

// read the question correctly (ll vs int)
// template by bqi343


// Problem : B. Working out
// Contest : Codeforces - Codeforces Round #245 (Div. 1)
// URL : https://codeforces.com/contest/429/problem/B
// Memory Limit : 256 MB
// Time Limit : 2000 ms
// Powered by CP Editor (https://github.com/cpeditor/cpeditor)

/*ヽ｀、ヽ｀｀、ヽ｀ヽ｀、、ヽ ｀ヽ 、ヽ｀🌙｀ヽヽ｀ヽ、ヽ｀
ヽ｀、ヽ｀｀、ヽ 、｀｀、 ｀、ヽ｀ 、｀ ヽ｀ヽ、ヽ ｀、ヽ｀｀、
ヽ、｀｀、｀、ヽ｀｀、 、ヽヽ｀、｀、、ヽヽ、｀｀、 、 ヽ｀、
ヽ｀｀、 ヽ｀ヽ｀、、ヽ ｀ヽ 、 🚶ヽ｀｀｀｀ヽヽヽ｀、、ヽ｀、、ヽ*/

// #pragma GCC optimize ("O3")
// #pragma GCC target ("sse4")

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,b,a) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
#define trav(a,x) for (auto& a : x)

#define bug(x) cout<<#x<<"="<<x<<endl;
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()
#define ins insert

template<class T> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const ld pii=3.14159265359;
const int MOD = 1000000007;
const char nl = '\n';
const int MX = 200001; //check the limits, dummy

int main()
{
	//binary search lag skta kya?
	ios_base::sync_with_stdio(0); cin.tie(0);
	int N,M;cin>>N>>M;
	vector<vi> v(N,vi(M));
	trav(i,v)
		trav(j,i)
			cin>>j;
	ll dp[4][N][M];
	F0R(x,N)F0R(y,M)F0R(z,4)dp[z][x][y]=0;

	int p=0;
	F0R(x,N)
	{
		F0R(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=0)
			{
				dp[p][x][y]+=dp[p][x-1][y];
			}
			if(y!=0)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y-1]);
			}
		}
	}
	p++;
	F0R(x,N)
	{
		F0Rd(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=0)
			{
				dp[p][x][y]+=dp[p][x-1][y];
			}
			if(y!=M-1)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y+1]);
			}
		}
	}
	p++;
	F0Rd(x,N)
	{
		F0Rd(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=N-1)
			{
				dp[p][x][y]+=dp[p][x+1][y];
			}
			if(y!=N-1)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y+1]);
			}
		}
	}
	p++;
	F0Rd(x,N)
	{
		F0R(y,M)
		{
			dp[p][x][y]=v[x][y];
			if(x!=N-1)
			{
				dp[p][x][y]+=dp[p][x+1][y];
			}
			if(y!=0)
			{
				ckmax(dp[p][x][y],v[x][y]+dp[p][x][y-1]);
			}
		}
	}
	ll ans=LLONG_MIN;
	F0R(x,N)
	{
		F0R(y,M)
		{
			ll r1,r2,r3,r4;
			r1=r2=r3=r4=0;
			if(x!=0)
			{
				r1=dp[0][x-1][y];
				r2=dp[1][x-1][y];
			}
			if(y!=0)
			{
				r4=dp[3][x][y-1];
				ckmax(r1,dp[0][x][y-1]);
			}
			if(x!=N-1)
			{
				ckmax(r4,dp[3][x+1][y]);
				ckmax(r3,dp[2][x+1][y]);
			}
			if(y!=M-1)
			{
				// ckmax(r4,dp[3][x][y+1]);
				ckmax(r2,dp[1][x][y+1]);
				ckmax(r3,dp[2][x][y+1]);
			}
			ckmax(ans,r1+r2+r3+r4);
		}
	}
	// trav(i,dp[0])
	// {
		// trav(j,i)
			// cout<<j<<' ';
		// cout<<nl;
	// }

	cout<<ans;
	return 0;
}

// read the question correctly (ll vs int)
// template by bqi343


#include<bits/stdc++.h>
#define ll  int
#define ull unsigned long long int
#define N (ll)(2 * (1e5+5) )

using namespace std;

ll n, m ;

ll a[3005][3005] , dp1[3005][3005] , dp2[3005][3005] , dp3[3005][3005], dp4[3005][3005];

ll get_dp1(ll i, ll j ) {

	if (i == n - 1 && j == m - 1 ) {
		return dp1[i][j] = a[i][j] ;
	}

	if ( i >= n || j >= m  )return -1e9 - 7 ;

	if ( dp1[i][j] != -1 )return dp1[i][j] ;

	return dp1[i][j] = max( get_dp1(i + 1, j) , get_dp1(i, j + 1) ) + a[i][j] ;

}

ll get_dp2(ll i, ll j ) {

	if (i == 0 && j == 0 ) {
		return dp2[i][j] = a[i][j] ;
	}

	if ( i < 0 || j < 0  )return -1e9 - 7 ;

	if ( dp2[i][j] != -1 )return dp2[i][j] ;

	return dp2[i][j] = max( get_dp2(i - 1, j) , get_dp2(i, j - 1) ) + a[i][j] ;

}

ll get_dp3(ll i, ll j ) {

	if (i == 0 && j == m - 1 ) {
		return dp3[i][j] = a[i][j] ;
	}

	if ( i < 0  || j >= m  )return -1e9 - 7 ;

	if ( dp3[i][j] != -1 )return dp3[i][j] ;

	return dp3[i][j] = max( get_dp3(i - 1, j) , get_dp3(i, j + 1) ) + a[i][j] ;

}

ll get_dp4(ll i, ll j ) {

	if (i == n - 1 && j == 0 ) {
		return dp4[i][j] = a[i][j] ;
	}

	if ( i >= n || j < 0  )return -1e9 - 7 ;

	if ( dp4[i][j] != -1 )return dp4[i][j] ;

	return dp4[i][j] = max( get_dp4(i + 1, j) , get_dp4(i, j - 1) ) + a[i][j] ;

}

int main()
{
	ios_base::sync_with_stdio(false) ;
	cin.tie(0) ;
	cout.tie(0) ;

#ifndef ONLINE_JUDGE

	freopen("input1.txt", "r", stdin) ;
	freopen("output1.txt", "w", stdout) ;

#endif

	ll t ;
	t  = 1 ;

	while (t--) {

		memset(dp1, -1, sizeof dp1) ; memset(dp2, -1, sizeof dp2) ;
		memset(dp3, -1, sizeof dp3) ; memset(dp4, -1, sizeof dp4) ;

		cin >> n >> m ;

		for (ll i = 0; i < n; i++)for (ll j = 0; j < m; j++) {
				cin >> a[i][j] ;

			}

		ll k ;

		k = get_dp1(0, 0) ;

		k = get_dp2(n - 1, m - 1) ;

		k = get_dp3(n - 1, 0) ;

		k = get_dp4(0, m - 1) ;

		long long ans = -1 ;

		for (ll i = 1 ; i < n - 1; i++) {
			for (ll j = 1; j < m - 1; j++) {

				long long k5 = dp2[i][j - 1] + dp1[i][j + 1] + dp4[i + 1][j] + dp3[i - 1][j] ;

				ans = max(   ans , k5 ) ;

				k5 = dp2[i - 1][j] + dp1[i + 1][j] + dp4[i][j - 1] + dp3[i][j + 1] ;

				ans = max(   ans , k5 ) ;

				//if ( k5 == ans )cout << i << " " << j << "\n" ;

				//if ( i == 2 && j == 3 )cout << dp1[i][j] + dp2[i][j] + dp3[i][j] + dp4[i][j] << "\n" ;

			}
		}

		cout << ans << "\n" ;

	}

}


#include<bits/stdc++.h>
#define ll  int
#define ull unsigned long long int
#define N (ll)(2 * (1e5+5) )

using namespace std;

ll n, m ;

ll a[3005][3005] , dp1[3005][3005] , dp2[3005][3005] , dp3[3005][3005], dp4[3005][3005];

ll get_dp1(ll i, ll j ) {

	if (i == n - 1 && j == m - 1 ) {
		return a[i][j] ;
	}

	if ( i >= n || j >= m  )return -1e9 - 7 ;

	if ( dp1[i][j] != -1 )return dp1[i][j] ;

	return dp1[i][j] = max( get_dp1(i + 1, j) , get_dp1(i, j + 1) ) + a[i][j] ;

}

ll get_dp2(ll i, ll j ) {

	if (i == 0 && j == 0 ) {
		return a[i][j] ;
	}

	if ( i < 0 || j < 0  )return -1e9 - 7 ;

	if ( dp2[i][j] != -1 )return dp2[i][j] ;

	return dp2[i][j] = max( get_dp2(i - 1, j) , get_dp2(i, j - 1) ) + a[i][j] ;

}

ll get_dp3(ll i, ll j ) {

	if (i == 0 && j == m - 1 ) {
		return a[i][j] ;
	}

	if ( i < 0  || j >= m  )return -1e9 - 7 ;

	if ( dp3[i][j] != -1 )return dp3[i][j] ;

	return dp3[i][j] = max( get_dp3(i - 1, j) , get_dp3(i, j + 1) ) + a[i][j] ;

}

ll get_dp4(ll i, ll j ) {

	if (i == n - 1 && j == 0 ) {
		return a[i][j] ;
	}

	if ( i >= n || j < 0  )return -1e9 - 7 ;

	if ( dp4[i][j] != -1 )return dp4[i][j] ;

	return dp4[i][j] = max( get_dp4(i + 1, j) , get_dp4(i, j - 1) ) + a[i][j] ;

}

int main()
{
	ios_base::sync_with_stdio(false) ;
	cin.tie(0) ;
	cout.tie(0) ;

#ifndef ONLINE_JUDGE

	freopen("input1.txt", "r", stdin) ;
	freopen("output1.txt", "w", stdout) ;

#endif

	ll t ;
	t  = 1 ;

	while (t--) {

		cin >> n >> m ;

		for (ll i = 0; i < n; i++)for (ll j = 0; j < m; j++) {
				cin >> a[i][j] ;
				dp1[i][j] = dp2[i][j] = dp3[i][j] = dp4[i][j] = -1 ;
			}

		ll k ;

		k = get_dp1(0, 0) ;

		k = get_dp2(n - 1, m - 1) ;

		k = get_dp3(n - 1, 0) ;

		k = get_dp4(0, m - 1) ;

		long long ans = -1 ;

		for (ll i = 0; i < n; i++) {
			for (ll j = 0; j < m; j++) {

				ans = max(   ans , (long long)(dp1[i][j] + dp2[i][j] + dp3[i][j] + dp4[i][j] - ( 4 *  ( a[i][j] ) ) )     ) ;

			}
		}

		cout << ans << "\n" ;

	}

}


#include<bits/stdc++.h>
#define ll int
#define ull unsigned long long int
#define N (ll)(2 * (1e5+5) )

using namespace std;

ll n, m ;

ll a[3005][3005] , dp1[3005][3005] , dp2[3005][3005] , dp3[3005][3005], dp4[3005][3005];

ll get_dp1(ll i, ll j ) {

	if (i == n - 1 && j == m - 1 ) {
		return a[i][j] ;
	}

	if ( i >= n || j >= m  )return -1e9 - 7 ;

	if ( dp1[i][j] != -1 )return dp1[i][j] ;

	return dp1[i][j] = max( get_dp1(i + 1, j) , get_dp1(i, j + 1) ) + a[i][j] ;

}

ll get_dp2(ll i, ll j ) {

	if (i == 0 && j == 0 ) {
		return a[i][j] ;
	}

	if ( i < 0 || j < 0  )return -1e9 - 7 ;

	if ( dp2[i][j] != -1 )return dp2[i][j] ;

	return dp2[i][j] = max( get_dp2(i - 1, j) , get_dp2(i, j - 1) ) + a[i][j] ;

}

ll get_dp3(ll i, ll j ) {

	if (i == 0 && j == m - 1 ) {
		return a[i][j] ;
	}

	if ( i < 0  || j >= m  )return -1e9 - 7 ;

	if ( dp3[i][j] != -1 )return dp3[i][j] ;

	return dp3[i][j] = max( get_dp3(i - 1, j) , get_dp3(i, j + 1) ) + a[i][j] ;

}

ll get_dp4(ll i, ll j ) {

	if (i == n - 1 && j == 0 ) {
		return a[i][j] ;
	}

	if ( i >= n || j < 0  )return -1e9 - 7 ;

	if ( dp4[i][j] != -1 )return dp4[i][j] ;

	return dp4[i][j] = max( get_dp4(i + 1, j) , get_dp4(i, j - 1) ) + a[i][j] ;

}

int main()
{
	ios_base::sync_with_stdio(false) ;
	cin.tie(0) ;
	cout.tie(0) ;

#ifndef ONLINE_JUDGE

	freopen("input1.txt", "r", stdin) ;
	freopen("output1.txt", "w", stdout) ;

#endif

	ll t ;
	t  = 1 ;

	while (t--) {

		cin >> n >> m ;

		for (ll i = 0; i < n; i++)for (ll j = 0; j < m; j++) {
				cin >> a[i][j] ;
				dp1[i][j] = dp2[i][j] = dp3[i][j] = dp4[i][j] = -1 ;
			}

		ll k ;

		k = get_dp1(0, 0) ;

		k = get_dp2(n - 1, m - 1) ;

		k = get_dp3(n - 1, 0) ;

		k = get_dp4(0, m - 1) ;

		long long ans = -1 ;

		for (ll i = 0; i < n; i++) {
			for (ll j = 0; j < m; j++) {

				ans = max(   ans , dp1[i][j] + dp2[i][j] + dp3[i][j] + dp4[i][j] - ( 4 *  ( a[i][j] ) )      ) ;

			}
		}

		cout << ans << "\n" ;

	}

}


#include<bits/stdc++.h>
#define ll long long int
#define ull unsigned long long int
#define N (ll)(2 * (1e5+5) )

using namespace std;

ll n, m ;

ll a[3005][3005] , dp1[3005][3005] , dp2[3005][3005] , dp3[3005][3005], dp4[3005][3005];

ll get_dp1(ll i, ll j ) {

	if (i == n - 1 && j == m - 1 ) {
		return a[i][j] ;
	}

	if ( i >= n || j >= m  )return -1e9 - 7 ;

	if ( dp1[i][j] != -1 )return dp1[i][j] ;

	return dp1[i][j] = max( get_dp1(i + 1, j) , get_dp1(i, j + 1) ) + a[i][j] ;

}

ll get_dp2(ll i, ll j ) {

	if (i == 0 && j == 0 ) {
		return a[i][j] ;
	}

	if ( i < 0 || j < 0  )return -1e9 - 7 ;

	if ( dp2[i][j] != -1 )return dp2[i][j] ;

	return dp2[i][j] = max( get_dp2(i - 1, j) , get_dp2(i, j - 1) ) + a[i][j] ;

}

ll get_dp3(ll i, ll j ) {

	if (i == 0 && j == m - 1 ) {
		return a[i][j] ;
	}

	if ( i < 0  || j >= m  )return -1e9 - 7 ;

	if ( dp3[i][j] != -1 )return dp3[i][j] ;

	return dp3[i][j] = max( get_dp3(i - 1, j) , get_dp3(i, j + 1) ) + a[i][j] ;

}

ll get_dp4(ll i, ll j ) {

	if (i == n - 1 && j == 0 ) {
		return a[i][j] ;
	}

	if ( i >= n || j < 0  )return -1e9 - 7 ;

	if ( dp4[i][j] != -1 )return dp4[i][j] ;

	return dp4[i][j] = max( get_dp4(i + 1, j) , get_dp4(i, j - 1) ) + a[i][j] ;

}

int main()
{
	ios_base::sync_with_stdio(false) ;
	cin.tie(0) ;
	cout.tie(0) ;

#ifndef ONLINE_JUDGE

	freopen("input1.txt", "r", stdin) ;
	freopen("output1.txt", "w", stdout) ;

#endif

	ll t ;
	t  = 1 ;

	while (t--) {

		cin >> n >> m ;

		for (ll i = 0; i < n; i++)for (ll j = 0; j < m; j++) {
				cin >> a[i][j] ;
				dp1[i][j] = dp2[i][j] = dp3[i][j] = dp4[i][j] = -1 ;
			}

		ll k ;

		k = get_dp1(0, 0) ;

		k = get_dp2(n - 1, m - 1) ;

		k = get_dp3(n - 1, 0) ;

		k = get_dp4(0, m - 1) ;

		ll ans = -1 ;

		for (ll i = 0; i < n; i++) {
			for (ll j = 0; j < m; j++) {

				ans = max(   ans , dp1[i][j] + dp2[i][j] + dp3[i][j] + dp4[i][j] - ( 4 *  ( a[i][j] ) )      ) ;

			}
		}

		cout << ans << "\n" ;

	}

}


/*************************************************
*   author: @Abhay                               *
*   National Institute of Technology, Patna      *
*   CSE:2K16                                     *
*************************************************/

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

//#define ONLINE_JUDGE
#define debug(x) cout<<x<<" ";
#define nl cout<<"\n";
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
//Change less to less_equal for a multiset (Beware! Deletion might cause problem)
#define rep(i,a,b) for(__typeof(b) i=a;i<b;i++)
#define rrep(i,b,a) for(__typeof(a) i=b;i>=a;i--)
#define printp(i,arr,n) rep(i,0,n) cout<<"("<<arr[i].fi<<","<<arr[i].se<<") ";
#define print(i,arr,n) rep(i,0,n) cout<<arr[i]<<" ";
#define println(i,arr,n) rep(i,0,n) cout<<arr[i]<<"\n";
#define scan(i,arr,n) rep(i,0,n) cin>>arr[i];
#define boost1 ios_base::sync_with_stdio(false);
#define boost2 cin.tie(0);cout.tie(0);
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define INF 0x3f3f3f3f
#define mod 1000000007

int main(){
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
    boost1 boost2
    int n,m; cin>>n>>m;
    ll mat[n][m],sum=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>mat[i][j];
            sum += mat[i][j];
        }
    }
    ll a[n][m],b[n][m],c[n][m],d[n][m];
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(i==0&&j==0) a[i][j] = mat[i][j];
            else if(i==0) a[i][j] = mat[i][j] + a[i][j-1];
            else if(j==0) a[i][j] = mat[i][j] + a[i-1][j];
            else a[i][j] = mat[i][j] + max(a[i-1][j],a[i][j-1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=0;j<m;j++){
            if(i==n-1&&j==0) b[i][j] = mat[i][j];
            else if(i==n-1) b[i][j] = mat[i][j] + b[i][j-1];
            else if(j==0) b[i][j] = mat[i][j] + b[i+1][j];
            else b[i][j] = mat[i][j] + max(b[i+1][j],b[i][j-1]);
        }
    }
    for(int i=0;i<n;i++){
        for(int j=m-1;j>=0;j--){
            if(i==0&&j==m-1) c[i][j] = mat[i][j];
            else if(i==0) c[i][j] = mat[i][j] + c[i][j+1];
            else if(j==m-1) c[i][j] = mat[i][j] + c[i-1][j];
            else c[i][j] = mat[i][j] + max(c[i-1][j],c[i][j+1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=m-1;j>=0;j--){
            if(i==n-1&&j==m-1) d[i][j] = mat[i][j];
            else if(i==n-1) d[i][j] = mat[i][j] + d[i][j+1];
            else if(j==m-1) d[i][j] = mat[i][j] + d[i+1][j];
            else d[i][j] = mat[i][j] + max(d[i+1][j],d[i][j+1]);
        }
    }
    if(n==3&&m==3){
        cout<<sum-mat[1][1]<<endl;
        return 0;
    }

    ll ans = 0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            ll u1=0,d1=0,l1=0,r1=0;
            ll u2=0,d2=0,l2=0,r2=0;

            if(i!=0) u1 = a[i-1][j];
            if(i!=n-1) d1 = d[i+1][j];
            if(j!=0) l1 = b[i][j-1];
            if(j!=m-1) r1 = c[i][j+1];

            if(i!=0) u2 = c[i-1][j];
            if(i!=n-1) d2 = b[i+1][j];
            if(j!=0) l2 = a[i][j-1];
            if(j!=m-1) r2 = d[i][j+1];

            if(i==0&&j==1) ans = max(ans,u2+d2+l2+r2);
            else if(i==1&&j==0) ans = max(ans,u1+d1+l1+r1);
            else if(i==n-2&&j==0) ans = max(ans,u1+d1+l1+r1);
            else if(i==n-1&&j==1) ans = max(ans,u2+d2+l2+r2);
            else if(i==n-1&&j==m-2) ans = max(ans,u2+d2+l2+r2);
            else if(i==n-2&&j==m-1) ans = max(ans,u1+d1+l1+r1);
            else if(i==0&&j==m-2) ans = max(ans,u2+d2+l2+r2);
            else if(i==1&&j==m-1) ans = max(ans,u1+d1+l1+r1);
            else ans = max(ans,max(u1+d1+l1+r1,u2+d2+l2+r2));
            cout<<i<<" "<<j<<" "<<ans<<endl;
        }//nl;
    }//nl;
    cout<<ans<<endl;
    return 0;
}


/*************************************************
*   author: @Abhay                               *
*   National Institute of Technology, Patna      *
*   CSE:2K16                                     *
*************************************************/

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

//#define ONLINE_JUDGE
#define debug(x) cout<<x<<" ";
#define nl cout<<"\n";
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
//Change less to less_equal for a multiset (Beware! Deletion might cause problem)
#define rep(i,a,b) for(__typeof(b) i=a;i<b;i++)
#define rrep(i,b,a) for(__typeof(a) i=b;i>=a;i--)
#define printp(i,arr,n) rep(i,0,n) cout<<"("<<arr[i].fi<<","<<arr[i].se<<") ";
#define print(i,arr,n) rep(i,0,n) cout<<arr[i]<<" ";
#define println(i,arr,n) rep(i,0,n) cout<<arr[i]<<"\n";
#define scan(i,arr,n) rep(i,0,n) cin>>arr[i];
#define boost1 ios_base::sync_with_stdio(false);
#define boost2 cin.tie(0);cout.tie(0);
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define INF 0x3f3f3f3f
#define mod 1000000007

int main(){
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
    boost1 boost2
    int n,m; cin>>n>>m;
    ll mat[n][m],sum=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>mat[i][j];
            sum += mat[i][j];
        }
    }
    ll a[n][m],b[n][m],c[n][m],d[n][m];
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(i==0&&j==0) a[i][j] = mat[i][j];
            else if(i==0) a[i][j] = mat[i][j] + a[i][j-1];
            else if(j==0) a[i][j] = mat[i][j] + a[i-1][j];
            else a[i][j] = mat[i][j] + max(a[i-1][j],a[i][j-1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=0;j<m;j++){
            if(i==n-1&&j==0) b[i][j] = mat[i][j];
            else if(i==n-1) b[i][j] = mat[i][j] + b[i][j-1];
            else if(j==0) b[i][j] = mat[i][j] + b[i+1][j];
            else b[i][j] = mat[i][j] + max(b[i+1][j],b[i][j-1]);
        }
    }
    for(int i=0;i<n;i++){
        for(int j=m-1;j>=0;j--){
            if(i==0&&j==m-1) c[i][j] = mat[i][j];
            else if(i==0) c[i][j] = mat[i][j] + c[i][j+1];
            else if(j==m-1) c[i][j] = mat[i][j] + c[i-1][j];
            else c[i][j] = mat[i][j] + max(c[i-1][j],c[i][j+1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=m-1;j>=0;j--){
            if(i==n-1&&j==m-1) d[i][j] = mat[i][j];
            else if(i==n-1) d[i][j] = mat[i][j] + d[i][j+1];
            else if(j==m-1) d[i][j] = mat[i][j] + d[i+1][j];
            else d[i][j] = mat[i][j] + max(d[i+1][j],d[i][j+1]);
        }
    }
    if(n==3&&m==3){
        cout<<sum-mat[1][1]<<endl;
        return 0;
    }

    ll ans = 0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            ll u1=0,d1=0,l1=0,r1=0;
            ll u2=0,d2=0,l2=0,r2=0;

            if(i!=0) u1 = a[i-1][j];
            if(i!=n-1) d1 = d[i+1][j];
            if(j!=0) l1 = b[i][j-1];
            if(j!=m-1) r1 = c[i][j+1];

            if(i!=0) u2 = c[i-1][j];
            if(i!=n-1) d2 = b[i+1][j];
            if(j!=0) l2 = a[i][j-1];
            if(j!=m-1) r2 = d[i][j+1];

            if(i==0&&j==1) ans = max(ans,u2+d2+l2+r2);
            else if(i==1&&j==0) ans = max(ans,u1+d1+l1+r1);
            else if(i==n-2&&j==0) ans = max(ans,u1+d1+l1+r1);
            else if(i==n-1&&j==1) ans = max(ans,u2+d2+l2+r2);
            else if(i==n-1&&j==m-2) ans = max(ans,u2+d2+l2+r2);
            else if(i==n-2&&j==m-1) ans = max(ans,u1+d1+l1+r1);
            else if(i==0&&j==m-2) ans = max(ans,u2+d2+l2+r2);
            else if(i==1&&j==m-1) ans = max(ans,u1+d1+l1+r1);
            else ans = max(ans,max(u1+d1+l1+r1,u2+d2+l2+r2));
            //cout<<i<<" "<<j<<" "<<ans<<endl;
        }//nl;
    }//nl;
    cout<<ans<<endl;
    return 0;
}


/*************************************************
*   author: @Abhay                               *
*   National Institute of Technology, Patna      *
*   CSE:2K16                                     *
*************************************************/

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

//#define ONLINE_JUDGE
#define debug(x) cout<<x<<" ";
#define nl cout<<"\n";
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
//Change less to less_equal for a multiset (Beware! Deletion might cause problem)
#define rep(i,a,b) for(__typeof(b) i=a;i<b;i++)
#define rrep(i,b,a) for(__typeof(a) i=b;i>=a;i--)
#define printp(i,arr,n) rep(i,0,n) cout<<"("<<arr[i].fi<<","<<arr[i].se<<") ";
#define print(i,arr,n) rep(i,0,n) cout<<arr[i]<<" ";
#define println(i,arr,n) rep(i,0,n) cout<<arr[i]<<"\n";
#define scan(i,arr,n) rep(i,0,n) cin>>arr[i];
#define boost1 ios_base::sync_with_stdio(false);
#define boost2 cin.tie(0);cout.tie(0);
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define INF 0x3f3f3f3f
#define mod 1000000007

int main(){
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
    boost1 boost2
    int n,m; cin>>n>>m;
    ll mat[n][m],sum=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>mat[i][j];
            sum += mat[i][j];
        }
    }
    ll a[n][m],b[n][m],c[n][m],d[n][m];
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(i==0&&j==0) a[i][j] = mat[i][j];
            else if(i==0) a[i][j] = mat[i][j] + a[i][j-1];
            else if(j==0) a[i][j] = mat[i][j] + a[i-1][j];
            else a[i][j] = mat[i][j] + max(a[i-1][j],a[i][j-1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=0;j<m;j++){
            if(i==n-1&&j==0) b[i][j] = mat[i][j];
            else if(i==n-1) b[i][j] = mat[i][j] + b[i][j-1];
            else if(j==0) b[i][j] = mat[i][j] + b[i+1][j];
            else b[i][j] = mat[i][j] + max(b[i+1][j],b[i][j-1]);
        }
    }
    for(int i=0;i<n;i++){
        for(int j=m-1;j>=0;j--){
            if(i==0&&j==m-1) c[i][j] = mat[i][j];
            else if(i==0) c[i][j] = mat[i][j] + c[i][j+1];
            else if(j==m-1) c[i][j] = mat[i][j] + c[i-1][j];
            else c[i][j] = mat[i][j] + max(c[i-1][j],c[i][j+1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=m-1;j>=0;j--){
            if(i==n-1&&j==m-1) d[i][j] = mat[i][j];
            else if(i==n-1) d[i][j] = mat[i][j] + d[i][j+1];
            else if(j==m-1) d[i][j] = mat[i][j] + d[i+1][j];
            else d[i][j] = mat[i][j] + max(d[i+1][j],d[i][j+1]);
        }
    }
    if(n==3&&m==3){
        cout<<sum-mat[1][1]<<endl;
        return 0;
    }

    ll ans = 0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            ll u1=0,d1=0,l1=0,r1=0;
            ll u2=0,d2=0,l2=0,r2=0;

            if(i!=0) u1 = a[i-1][j];
            if(i!=n-1) d1 = d[i+1][j];
            if(j!=0) l1 = b[i][j-1];
            if(j!=m-1) r1 = c[i][j+1];

            if(i!=0) u2 = c[i-1][j];
            if(i!=n-1) d2 = b[i+1][j];
            if(j!=0) l2 = a[i][j-1];
            if(j!=m-1) r2 = d[i][j+1];

            ans = max(ans,max(u1+d1+l1+r1,u2+d2+l2+r2));
            //cout<<i<<" "<<j<<" "<<ans<<endl;
        }//nl;
    }//nl;
    cout<<ans<<endl;
    return 0;
}


/*************************************************
*   author: @Abhay                               *
*   National Institute of Technology, Patna      *
*   CSE:2K16                                     *
*************************************************/

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

//#define ONLINE_JUDGE
#define debug(x) cout<<x<<" ";
#define nl cout<<"\n";
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
//Change less to less_equal for a multiset (Beware! Deletion might cause problem)
#define rep(i,a,b) for(__typeof(b) i=a;i<b;i++)
#define rrep(i,b,a) for(__typeof(a) i=b;i>=a;i--)
#define printp(i,arr,n) rep(i,0,n) cout<<"("<<arr[i].fi<<","<<arr[i].se<<") ";
#define print(i,arr,n) rep(i,0,n) cout<<arr[i]<<" ";
#define println(i,arr,n) rep(i,0,n) cout<<arr[i]<<"\n";
#define scan(i,arr,n) rep(i,0,n) cin>>arr[i];
#define boost1 ios_base::sync_with_stdio(false);
#define boost2 cin.tie(0);cout.tie(0);
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define INF 0x3f3f3f3f
#define mod 1000000007

int main(){
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
    boost1 boost2
    int n,m; cin>>n>>m;
    ll mat[n][m];
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>mat[i][j];
        }
    }
    ll a[n][m],b[n][m],c[n][m],d[n][m];
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(i==0&&j==0) a[i][j] = mat[i][j];
            else if(i==0) a[i][j] = mat[i][j] + a[i][j-1];
            else if(j==0) a[i][j] = mat[i][j] + a[i-1][j];
            else a[i][j] = mat[i][j] + max(a[i-1][j],a[i][j-1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=0;j<m;j++){
            if(i==n-1&&j==0) b[i][j] = mat[i][j];
            else if(i==n-1) b[i][j] = mat[i][j] + b[i][j-1];
            else if(j==0) b[i][j] = mat[i][j] + b[i+1][j];
            else b[i][j] = mat[i][j] + max(b[i+1][j],b[i][j-1]);
        }
    }
    for(int i=0;i<n;i++){
        for(int j=m-1;j>=0;j--){
            if(i==0&&j==m-1) c[i][j] = mat[i][j];
            else if(i==0) c[i][j] = mat[i][j] + c[i][j+1];
            else if(j==m-1) c[i][j] = mat[i][j] + c[i-1][j];
            else c[i][j] = mat[i][j] + max(c[i-1][j],c[i][j+1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=m-1;j>=0;j--){
            if(i==n-1&&j==m-1) d[i][j] = mat[i][j];
            else if(i==n-1) d[i][j] = mat[i][j] + d[i][j+1];
            else if(j==m-1) d[i][j] = mat[i][j] + d[i+1][j];
            else d[i][j] = mat[i][j] + max(d[i+1][j],d[i][j+1]);
        }
    }

    ll ans = 0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            ans = max(ans,a[i][j]+b[i][j]+c[i][j]+d[i][j]-4*mat[i][j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}


/*************************************************
*   author: @Abhay                               *
*   National Institute of Technology, Patna      *
*   CSE:2K16                                     *
*************************************************/

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

//#define ONLINE_JUDGE
#define debug(x) cout<<x<<" ";
#define nl cout<<"\n";
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
//Change less to less_equal for a multiset (Beware! Deletion might cause problem)
#define rep(i,a,b) for(__typeof(b) i=a;i<b;i++)
#define rrep(i,b,a) for(__typeof(a) i=b;i>=a;i--)
#define printp(i,arr,n) rep(i,0,n) cout<<"("<<arr[i].fi<<","<<arr[i].se<<") ";
#define print(i,arr,n) rep(i,0,n) cout<<arr[i]<<" ";
#define println(i,arr,n) rep(i,0,n) cout<<arr[i]<<"\n";
#define scan(i,arr,n) rep(i,0,n) cin>>arr[i];
#define boost1 ios_base::sync_with_stdio(false);
#define boost2 cin.tie(0);cout.tie(0);
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define INF 0x3f3f3f3f
#define mod 1000000007

int main(){
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
    boost1 boost2
    int n,m; cin>>n>>m;
    ll mat[n][m],v[n*m],k=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>mat[i][j];
            v[k++] = mat[i][j];
        }
    }
    // sort(v,v+k);
    // for(int i=0;i<k;i++){
    //     cout<<i+1<<" "<<v[i]<<endl;
    // }nl;
    ll a[n][m],b[n][m],c[n][m],d[n][m];
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(i==0&&j==0) a[i][j] = mat[i][j];
            else if(i==0) a[i][j] = mat[i][j] + a[i][j-1];
            else if(j==0) a[i][j] = mat[i][j] + a[i-1][j];
            else a[i][j] = mat[i][j] + max(a[i-1][j],a[i][j-1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=0;j<m;j++){
            if(i==n-1&&j==0) b[i][j] = mat[i][j];
            else if(i==n-1) b[i][j] = mat[i][j] + b[i][j-1];
            else if(j==0) b[i][j] = mat[i][j] + b[i+1][j];
            else b[i][j] = mat[i][j] + max(b[i+1][j],b[i][j-1]);
        }
    }
    for(int i=0;i<n;i++){
        for(int j=m-1;j>=0;j--){
            if(i==0&&j==m-1) c[i][j] = mat[i][j];
            else if(i==0) c[i][j] = mat[i][j] + c[i][j+1];
            else if(j==m-1) c[i][j] = mat[i][j] + c[i-1][j];
            else c[i][j] = mat[i][j] + max(c[i-1][j],c[i][j+1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=m-1;j>=0;j--){
            if(i==n-1&&j==m-1) d[i][j] = mat[i][j];
            else if(i==n-1) d[i][j] = mat[i][j] + d[i][j+1];
            else if(j==m-1) d[i][j] = mat[i][j] + d[i+1][j];
            else d[i][j] = mat[i][j] + max(d[i+1][j],d[i][j+1]);
        }
    }

    ll ans = 0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            //cout<<a[i][j]+b[i][j]+c[i][j]+d[i][j]-4*mat[i][j]<<" ";
            ll u1=0,d1=0,l1=0,r1=0;
            ll u2=0,d2=0,l2=0,r2=0;

            if(i!=0) u1 = a[i-1][j];
            if(i!=n-1) d1 = d[i+1][j];
            if(j!=0) l1 = b[i][j-1];
            if(j!=m-1) r1 = c[i][j+1];

            if(i!=0) u2 = c[i-1][j];
            if(i!=n-1) d2 = b[i+1][j];
            if(j!=0) l2 = a[i][j-1];
            if(j!=m-1) r2 = d[i][j+1];

            ans = max(ans,max(u1+d1+l1+r1,u2+d2+l2+r2));
        }//nl;
    }//nl;

    cout<<ans<<endl;
    return 0;
}


/*************************************************
*   author: @Abhay                               *
*   National Institute of Technology, Patna      *
*   CSE:2K16                                     *
*************************************************/

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

//#define ONLINE_JUDGE
#define debug(x) cout<<x<<" ";
#define nl cout<<"\n";
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
//Change less to less_equal for a multiset (Beware! Deletion might cause problem)
#define rep(i,a,b) for(__typeof(b) i=a;i<b;i++)
#define rrep(i,b,a) for(__typeof(a) i=b;i>=a;i--)
#define printp(i,arr,n) rep(i,0,n) cout<<"("<<arr[i].fi<<","<<arr[i].se<<") ";
#define print(i,arr,n) rep(i,0,n) cout<<arr[i]<<" ";
#define println(i,arr,n) rep(i,0,n) cout<<arr[i]<<"\n";
#define scan(i,arr,n) rep(i,0,n) cin>>arr[i];
#define boost1 ios_base::sync_with_stdio(false);
#define boost2 cin.tie(0);cout.tie(0);
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define INF 0x3f3f3f3f
#define mod 1000000007

int main(){
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
    boost1 boost2
    int n,m; cin>>n>>m;
    ll mat[n][m];
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>mat[i][j];
        }
    }
    ll a[n][m],b[n][m],c[n][m],d[n][m];
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(i==0&&j==0) a[i][j] = mat[i][j];
            else if(i==0) a[i][j] = mat[i][j] + a[i][j-1];
            else if(j==0) a[i][j] = mat[i][j] + a[i-1][j];
            else a[i][j] = mat[i][j] + max(a[i-1][j],a[i][j-1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=0;j<m;j++){
            if(i==n-1&&j==0) b[i][j] = mat[i][j];
            else if(i==n-1) b[i][j] = mat[i][j] + b[i][j-1];
            else if(j==0) b[i][j] = mat[i][j] + b[i+1][j];
            else b[i][j] = mat[i][j] + max(b[i+1][j],b[i][j-1]);
        }
    }
    for(int i=0;i<n;i++){
        for(int j=m-1;j>=0;j--){
            if(i==0&&j==m-1) c[i][j] = mat[i][j];
            else if(i==0) c[i][j] = mat[i][j] + c[i][j+1];
            else if(j==m-1) c[i][j] = mat[i][j] + c[i-1][j];
            else c[i][j] = mat[i][j] + max(c[i-1][j],c[i][j+1]);
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=m-1;j>=0;j--){
            if(i==n-1&&j==m-1) d[i][j] = mat[i][j];
            else if(i==n-1) d[i][j] = mat[i][j] + d[i][j+1];
            else if(j==m-1) d[i][j] = mat[i][j] + d[i+1][j];
            else d[i][j] = mat[i][j] + max(d[i+1][j],d[i][j+1]);
        }
    }

    ll ans = 0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            ll u1=0,d1=0,l1=0,r1=0;
            ll u2=0,d2=0,l2=0,r2=0;

            if(i!=0) u1 = a[i-1][j];
            if(i!=n-1) d1 = d[i+1][j];
            if(j!=0) l1 = b[i][j-1];
            if(j!=m-1) r1 = c[i][j+1];

            if(i!=0) u2 = c[i-1][j];
            if(i!=n-1) d2 = b[i+1][j];
            if(j!=0) l2 = a[i][j-1];
            if(j!=m-1) r2 = d[i][j+1];

            if(i==0&&j==1) ans = max(ans,u2+d2+l2+r2);
            else if(i==1&&j==0) ans = max(ans,u1+d1+l1+r1);
            else if(i==n-2&&j==0) ans = max(ans,u1+d1+l1+r1);
            else if(i==n-1&&j==1) ans = max(ans,u2+d2+l2+r2);
            else if(i==n-1&&j==m-2) ans = max(ans,u2+d2+l2+r2);
            else if(i==n-2&&j==m-1) ans = max(ans,u1+d1+l1+r1);
            else if(i==0&&j==m-2) ans = max(ans,u2+d2+l2+r2);
            else if(i==1&&j==m-1) ans = max(ans,u1+d1+l1+r1);
            else ans = max(ans,max(u1+d1+l1+r1,u2+d2+l2+r2));
            //cout<<i<<" "<<j<<" "<<ans<<endl;
        }//nl;
    }//nl;
    cout<<ans<<endl;
    return 0;
}


#include<iostream>
using namespace std ;
#define ll long long int
#include<vector>

    ll n , m ;

    vector<vector<ll>> dp1 , dp2 ,revdp1 , revdp2  , arr ;
void fil1( ll i , ll j )
{
    if(i>= n || i<0 || j >=m || j< 0  )
        return  ;

    if(dp1[i][j] !=-1)
        return ;

    fil1( i+1 , j) ;
    fil1( i , j+1) ;

    ll ans = 0 ;
    if(i+1 <= n-1 )
        ans = max( ans  , dp1[i+1 ][j]) ;
    if( j+1  < m)
        ans = max( ans , dp1[i][j+1] ) ;

    dp1[i][j] = arr[i][j] +ans ;

}

void revdil1( ll i , ll j )
{
    if(i>= n || i<0 || j >=m || j< 0  )
        return  ;

    if(revdp1[i][j] !=-1)
        return ;

    revdil1( i-1 , j) ;
    revdil1( i , j-1) ;

    ll ans = 0 ;
    if(i-1 >=0  )
        ans = max( ans  , revdp1[i-1 ][j]) ;
    if( j-1 >= 0 )
        ans = max( ans , revdp1[i][j-1] ) ;

    revdp1[i][j] = arr[i][j] +ans ;

}

void fil2( ll i , ll j )
{
    if(i>= n || i<0 || j >=m || j< 0  )
        return  ;

    if(dp2[i][j] !=-1)
        return ;

    fil2( i-1 , j) ;
    fil2( i , j+1) ;

    ll ans = 0 ;
    if(i-1 >= 0  )
        ans = max( ans  , dp2[i-1 ][j]) ;
    if( j+1  < m)
        ans = max( ans , dp2[i][j+1] ) ;

    dp2[i][j] = arr[i][j] +ans ;

}

void revdil2( ll i , ll j )
{
    if(i>= n || i<0 || j >=m || j< 0  )
        return  ;

    if(revdp2[i][j] !=-1)
        return ;

    revdil2( i+1 , j) ;
    revdil2( i , j-1) ;

    ll ans = 0 ;
    if(i+1 < n  )
        ans = max( ans  , revdp2[i+1 ][j]) ;
    if( j-1 >= 0 )
        ans = max( ans , revdp2[i][j-1] ) ;

    revdp2[i][j] = arr[i][j] +ans ;

}

int main()
{

    cin>>n>> m;
    vector<vector<ll>> brr( n , vector<ll>(m) ) ;
arr = brr ;
    for(ll i =0;i< n ;i++ )
        for(ll j =0 ;j < m ;j++)
        arr[i][j] = -1 ;

    dp1 = arr ;
    dp2 = arr ;
    revdp1 = arr ;
    revdp2 = arr ;

    for(ll i =0;i<n ;i++)
        for(ll j =0;j <m ;j++)
        cin>>arr[i][j] ;

    fil1( 0 ,0 ) ;
    fil2( n-1  ,0 ) ;
    revdil1 ( n-1   , m-1 ) ;
    revdil2( 0 , m-1    ) ;

ll ans= 0 ;

vector <pair< ll ,ll > >  bef1 = {  { 0 , -1}   , {-1 , 0} } ,  bef2 = { {0 , -1 }  , {1 , 0} }  , aft1 = { { 1, 0} , {  0 , 1 } } , aft2 = { {-1 , 0 } , {0 , 1}  } ;
for( auto i :  bef1 )
    ll h = 0 ;

    for(ll i =0;i < n ;i++ )
    {

        for(ll j =0;j < m ;j++ )
        {

for( auto b1 : bef1 )
{

    for(auto b2 : bef2 )
    {

        for( auto a1 :  aft1 )
        {

            for(auto a2 : aft2)
            {

                ll ob1x = i+b1.first  , ob1y = j+b1.second ;

                ll  tb1x = i+b2.first , tb1y  = j+b2.second ;

                ll ob2x = i+a1.first  , ob2y = j+a1.second ;

                ll  tb2x = i+a2.first , tb2y  = j+a2.second ;

                if( ( ob1x== tb1x  && ob1y==tb1y ) ||  ( ob2x== tb2x  && ob2y==tb2y )  || ( ob2x== tb1x  && ob2y==tb1y )   || ( ob1x== tb2x  && ob1y==tb2y ) || ( ob1x== ob2x  && ob1y==ob2y ) || ( ob2x==tb2x && ob2y== tb2y)  || ( ob1x==tb2x && ob1y==tb2y ) ||  ( ob2x==tb1x && ob2y==tb1y ) )
                                       continue ;

                                       // check for on

                                       if( !( i==0 && j==0 )   )
                                       {

                                           if( ob1x <0 || ob1y<0 || ob1x >n-1 || ob1y >m-1 )
                                            continue;
                                       }

                                       if( !( i==n-1 && j==m-1 )   )
                                       {

                                           if( ob2x <0 || ob2y<0 || ob2x >n-1 || ob2y >m-1 )
                                            continue;

                                       }

                                       if( !( i==n-1  && j==0 )   )
                                       {

                                           if( tb1x <0 || tb1y<0 || tb1x >n-1 || tb1y >m-1 )
                                            continue;
                                       }

                                       if( !( i==0 && j==m-1 )   )
                                       {

                                           if( tb2x <0 || tb2y<0 || tb2x >n-1 || tb2y >m-1 )
                                            continue;

                                       }

                ll sum = 0;

                if( ( ob1x>=0 && ob1x <n ) && ( ob1y>=0 && ob1y <m ) )
                    sum+= revdp1[ob1x][ob1y] ;

                if( ( ob2x>=0 && ob2x <n ) && ( ob2y>=0 && ob2y <m ) )
                    sum+= dp1[ob2x][ob2y] ;

                if( ( tb1x>=0 && tb1x <n ) && ( tb1y>=0 && tb1y <m ) )
                    sum+= revdp2[tb1x][tb1y] ;

                if( ( tb2x>=0 && tb2x <n ) && ( tb2y>=0 && tb2y <m ) )
                    sum+= dp2[tb2x][tb2y] ;

                    ans = max( sum  , ans );

            }
        }
    }
}

        }
    }

cout<< ans<<endl ;

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		int tries = 0;

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			tries++;
			Point2D.Double p = points.get(i);

			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			for (int j =0; j < points.size(); j ++) {

				if (j<0)
					j=0;

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

						map.put(slope, points.get(j));

					}

				}else {

					if (points.get(j).getX() == soloX) {

						map.put(slope, points.get(j));

					}

				}

			}

		}

		System.out.println(map.size());

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		int tries = 0;

		for (int i =0; i < points.size(); i ++) {

			System.out.println(points);

			Double slope = (points.get(i).getY() - soloY) / (points.get(i).getX() - soloX);

			int numCanGoThrough = 1;

			for (int j =0; j < points.size(); j ++) {

				if (points.get(i).getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {
						numCanGoThrough++;
						points.remove(j);
						if (i!=0)
							i--;
					}

				}else {

					if (points.get(j).getX() == soloX) {

						numCanGoThrough++;
						points.remove(j);

						if (i!=0)
							i--;

					}

				}

			}

			tries++;

		}

		System.out.println(tries);

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			Point2D.Double p = points.get(i);
			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			for (int j =0; j < points.size(); j ++) {

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

						map.put(slope, points.get(j));

					}
				}else {

					if (points.get(j).getX() == soloX)
						map.put(Double.MAX_VALUE, points.get(j));

				}

			}

		}

		boolean zeroThere = true;
		int count =0;
		for (Double d : map.keySet()) {

			if (d == 0.0 && !zeroThere)
				count--;

			if (d == 0.0)
				zeroThere = false;

			count++;

		}

		//if (targets == 2)
			//System.out.println(map);

		System.out.println(count);

		if (targets == 1000)
			System.out.println(map.size());

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			Point2D.Double p = points.get(i);
			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			if (p.getX() == soloX)
				map.put(Double.MAX_VALUE, p);
			else
				map.put(slope, p);

		}

		boolean zeroThere = true;
		int count =0;
		for (Double d : map.keySet()) {

			if (d == 0.0 && !zeroThere)
				count--;

			if (d == 0.0)
				zeroThere = false;

			count++;

		}

		//if (targets == 2)
			//System.out.println(map);

		System.out.println(count);

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			Point2D.Double p = points.get(i);
			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			for (int j =0; j < points.size(); j ++) {

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

						map.put(slope, points.get(j));

					}
				}else {

					if (points.get(j).getX() == soloX)
						map.put(Double.MAX_VALUE, points.get(j));

				}

			}

		}

		if (targets == 100)
			System.out.println(map);

		System.out.println(map.size());

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		int tries = 0;

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			tries++;
			Point2D.Double p = points.get(i);

			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			for (int j =0; j < points.size(); j ++) {

				if (j<0)
					j=0;

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

						map.put(slope, points.get(j));

					}

				}else {

					if (points.get(j).getX() == soloX) {

						map.put(-1.0, points.get(j));

					}

				}

			}

		}

		System.out.println(map.size());

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();
		boolean maxUsed = false;

		for ( int i=0; i < points.size(); i ++) {

			Point2D.Double p = points.get(i);
			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			for (int j =0; j < points.size(); j ++) {

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

						map.put(slope, points.get(j));

					}
				}else {

					map.put(Double.MAX_VALUE, points.get(j));
					maxUsed = true;

				}

			}

		}

		if (maxUsed)
			System.out.println(map.size()-1);
		else
			System.out.println(map.size());

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			Point2D.Double p = points.get(i);
			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			if (p.getX() == soloX)
				map.put(Double.MAX_VALUE, p);
			else
				map.put(slope, p);

		}

		boolean zeroThere = true;
		int count =0;
		for (Double d : map.keySet()) {

			if (d == 0.0 && !zeroThere)
				count--;

			if (d == 0.0)
				zeroThere = false;

			count++;

		}

		//if (targets == 2)
			//System.out.println(map);

		System.out.println(count);

		if (targets == 1000)
			System.out.println(map.size());

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		int tries = 0;

		for (int i =0; i < points.size(); i ++) {

			Double slope = (points.get(i).getY() - soloY) / (points.get(i).getX() - soloX);

			int numCanGoThrough = 1;

			for (int j =0; j < points.size(); j ++) {

				if (points.get(i).getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {
						numCanGoThrough++;
						points.remove(j);
						j--;
					}

				}else {

					if (points.get(j).getX() == soloX) {

						numCanGoThrough++;
						points.remove(j);
						j--;

					}

				}

			}

			tries++;

		}

		System.out.println(tries);

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			Point2D.Double p = points.get(i);
			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			for (int j =0; j < points.size(); j ++) {

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

						map.put(slope, points.get(j));

					}
				}else {

					map.put(Double.MAX_VALUE, points.get(j));

				}

			}

		}

		System.out.println(map.size());

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		int tries = 0;

		for (int i =0; i < points.size(); i ++) {

			Double slope = (points.get(i).getY() - soloY) / (points.get(i).getX() - soloX);

			int numCanGoThrough = 1;

			for (int j =0; j < points.size(); j ++) {

				if (points.get(i).getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {
						numCanGoThrough++;
						points.remove(j);
						if (i!=0)
							i--;
					}

				}else {

					if (points.get(j).getX() == soloX) {

						numCanGoThrough++;
						points.remove(j);

						if (i!=0)
							i--;

					}

				}

			}

			tries++;

		}

		System.out.println(tries);

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		int tries = 0;

		int i =0;

		for (; i < points.size(); i ++) {

			if (i<0) {
				i=0;
			}

			// System.out.println(points);

			if (points.size() != 0) {
			Point2D.Double p = points.get(i);

			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			int numCanGoThrough = 1;

			for (int j =0; j < points.size(); j ++) {

				if (j<0)
					j=0;

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

					//	System.out.println(points.get(j).getX() + "  " + slope);
					//	System.out.println(slope * (points.get(j).getX() - soloX) + soloY );
						numCanGoThrough++;
						points.remove(j);
						i--;
						j--;
					}

				}else {

					if (points.get(j).getX() == soloX) {
						//System.out.println(points.get(j).getX() + "  " + slope);

						numCanGoThrough++;
						points.remove(j);
						i--;
						j--;

					}

				}

			}

			tries++;

			}
		}

		System.out.println(tries);

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			Point2D.Double p = points.get(i);
			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			for (int j =0; j < points.size(); j ++) {

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

						map.put(slope, points.get(j));

					}
				}else {

					if (points.get(j).getX() == soloX)
						map.put(Double.MAX_VALUE, points.get(j));

				}

			}

		}

		int count =0;
		for (Double d : map.keySet()) {

			if (d != -0.0)
				count++;
		}

		System.out.println(map.size());

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		int tries = 0;

		int i =0;

		for (; i < points.size(); i ++) {

			if (i<0) {
				i=0;
			}

			// System.out.println(points);

			if (points.size() != 0) {

			tries++;
			Point2D.Double p = points.get(i);

			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			int numCanGoThrough = 1;

			for (int j =0; j < points.size(); j ++) {

				if (j<0)
					j=0;

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

					//	System.out.println(points.get(j).getX() + "  " + slope);
					//	System.out.println(slope * (points.get(j).getX() - soloX) + soloY );
						numCanGoThrough++;
						points.remove(j);
						i--;
						j--;
					}

				}else {

					if (points.get(j).getX() == soloX) {
						//System.out.println(points.get(j).getX() + "  " + slope);

						numCanGoThrough++;
						points.remove(j);
						i--;
						j--;

					}

				}

			}

			}
		}

		System.out.println(tries);

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			Point2D.Double p = points.get(i);
			Double slope = (p.getY() - soloY) / (p.getX() - soloX);
			map.put(slope, p);

		}

		boolean zeroThere = true;
		int count =0;
		for (Double d : map.keySet()) {

			if (d == 0.0 && !zeroThere)
				count--;

			if (d == 0.0)
				zeroThere = false;

			count++;

		}

		//if (targets == 2)
			//System.out.println(map);

		System.out.println(count);

		if (targets == 1000)
			System.out.println(map.size());

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			Point2D.Double p = points.get(i);
			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			for (int j =0; j < points.size(); j ++) {

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

						map.put(slope, points.get(j));

					}
				}else {

					if (points.get(j).getX() == soloX)
						map.put(Double.MAX_VALUE, points.get(j));

				}

			}

		}

		boolean zeroThere = true;
		int count =0;
		for (Double d : map.keySet()) {

			if (d == 0.0 && !zeroThere)
				count--;

			if (d == 0.0)
				zeroThere = false;

			count++;

		}

		//if (targets == 2)
			//System.out.println(map);

		System.out.println(count);
		//System.out.println(map.size());

	}

}


import java.util.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.*;

public class HanSolo {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int targets = scan.nextInt();
		double soloX = scan.nextDouble();
		double soloY = scan.nextDouble();
		scan.nextLine();

		ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();

		for (int i =0; i < targets; i++) {

			String s = scan.nextLine();
			Scanner lineScanner = new Scanner(s);
			double x = lineScanner.nextDouble();
			double y = lineScanner.nextDouble();
			points.add(new Point2D.Double(x, y));

		}

		HashMap <Double, Point2D.Double > map = new HashMap <Double, Point2D.Double>();

		for ( int i=0; i < points.size(); i ++) {

			Point2D.Double p = points.get(i);
			Double slope = (p.getY() - soloY) / (p.getX() - soloX);

			for (int j =0; j < points.size(); j ++) {

				if (p.getX() - soloX != 0) {

					if ( slope * (points.get(j).getX() - soloX) + soloY == points.get(j).getY()) {

						map.put(slope, points.get(j));

					}
				}else {

					if (points.get(j).getX() == soloX)
						map.put(Double.MAX_VALUE, points.get(j));

				}

			}

		}

		int count =0;
		for (Double d : map.keySet()) {

			if (d != -0.0)
				count++;
		}

		//if (targets == 2)
		//	System.out.println(map);

		System.out.println(count);

	}

}


import java.awt.*;
import java.io.*;
import java.util.HashSet;
import java.util.Iterator;
import java.util.StringTokenizer;

public class Main {
    static class FastReader {
        BufferedReader br;
        StringTokenizer st;

        public FastReader() {
            br = new BufferedReader(new
                    InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }

        String nextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }

    static FastReader sc = new FastReader();

    public static void main(String[] args) throws IOException {
        int n = sc.nextInt();
        int x = sc.nextInt();
        int y = sc.nextInt();
        int v = 0,h = 0;
        HashSet<Double> hs = new HashSet<Double>();
        for (int i = 0; i < n; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();

            if (a == x) {
                v = 1;
            }else if(b == y){
                h = 1;
            } else {
                double slope = ((b - y) / (double) (a - x));
                slope = Double.parseDouble(String.format("%.10f", slope));
                hs.add(slope);
            }
        }
        System.out.println(hs.size() + v+h);

    }

}