unittest
{
	assert( [ "2 2 3", "1 1 3", "2 1 4", "1 2 5" ].solve == 8 );
	assert( [ "2 5 5", "1 1 3", "2 4 20", "1 2 1", "1 3 4", "1 4 2" ].solve == 29 );
	assert( [ "4 5 10", "2 5 12", "1 5 12", "2 3 15", "1 2 20", "1 1 28", "2 4 26", "3 2 27", "4 5 21", "3 5 10", "1 3 10" ].solve == 142 );
}



import std.algorithm;
import std.conv;
import std.format;
import std.range;
import std.stdio;

void main()
{
	stdin.byLineCopy.solve.writeln;
}

auto solve( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto r = 0L;
	auto c = 0L;
	auto k = 0L;
	input.front.formattedRead!"%s %s %s"( r, c, k );
	auto rcvs = new long[ 3 ][ k ];
	auto ass = new long[][]( r, c );
	foreach( i; 0L .. k )
	{
		input.popFront;
		auto rcv = input.front.split.to!( long[] );
		ass[ rcv[ 0 ] - 1 ][ rcv[ 1 ] - 1 ] = rcv[ 2 ];
	}
	
	// dp[ y行目 ][ x列目 ][ 同じ行で拾ったアイテムの数 ] = 価値の合計
	const Z = 4;
	auto dp = new long[][][]( r, c, Z );
	foreach( y; 0L .. r )
	{
		foreach( x; 0L .. c )
		{
			foreach( z; 0L .. Z )
			{
				// アイテムを拾って移動する場合
				if( z + 1 < Z )
				{
					if( y + 1 < r ) dp[ y + 1 ][ x ][ 0 ] = max( dp[ y + 1 ][ x ][ 0 ], dp[ y ][ x ][ z ] + ass[ y ][ x ] );
					if( x + 1 < c ) dp[ y ][ x + 1 ][ z + 1 ] = max( dp[ y ][ x + 1 ][ z + 1 ], dp[ y ][ x ][ z ] + ass[ y ][ x ] );
				}
				
				// アイテムを拾わずに移動する場合
				if( y + 1 < r ) dp[ y + 1 ][ x ][ 0 ] = max( dp[ y + 1 ][ x ][ 0 ], dp[ y ][ x ][ z ] );
				if( x + 1 < c ) dp[ y ][ x + 1 ][ z ] = max( dp[ y ][ x + 1 ][ z ], dp[ y ][ x ][ z ] );
			}
		}
	}
	
	auto ans = 0L;
	foreach( z; 0L .. Z )
	{
		// アイテムを拾う場合
		if( z + 1 < Z ) ans = max( ans, dp[ $ - 1 ][ $ - 1 ][ z ] + ass[ $ - 1 ][ $ - 1 ] );
		
		// アイテムを拾わない場合
		ans = max( ans, dp[ $ - 1 ][ $ - 1 ][ z ] );
	}
	return ans;
}
