Problem:
Score : 800 points

Problem Statement

There is a grid with R rows and C columns.
We call the cell in the r-th row and c-th column (r，c).

Mr. Takahashi wrote non-negative integers into N of the cells, that is, he wrote a non-negative integer a_i into (r_i，c_i) for each i (1≤i≤N).
After that he fell asleep.

Mr. Aoki found the grid and tries to surprise Mr. Takahashi by writing integers into all remaining cells.
The grid must meet the following conditions to really surprise Mr. Takahashi.

Condition 1: Each cell contains a non-negative integer.

Condition 2: For any 2×2 square formed by cells on the grid, the sum of the top left and bottom right integers must always equal to the sum of the top right and bottom left integers.

Determine whether it is possible to meet those conditions by properly writing integers into all remaining cells.

Constraints

2≤R，C≤10^5

1≤N≤10^5

1≤r_i≤R

1≤c_i≤C

(r_i，c_i) ≠ (r_j，c_j) (i≠j)

a_i is an integer.

0≤a_i≤10^9

Input

The input is given from Standard Input in the following format:

R C
N
r_1 c_1 a_1
r_2 c_2 a_2
:
r_N c_N a_N

Output

Print Yes if it is possible to meet the conditions by properly writing integers into all remaining cells.
Otherwise, print No.

Sample Input 1

2 2
3
1 1 0
1 2 10
2 1 20

Sample Output 1

Yes

You can write integers as follows.

Sample Input 2

2 3
5
1 1 0
1 2 10
1 3 20
2 1 30
2 3 40

Sample Output 2

No

There are two 2×2 squares on the grid, formed by the following cells:

Cells (1，1), (1，2), (2，1) and (2，2)

Cells (1，2), (1，3), (2，2) and (2，3)

You have to write 40 into the empty cell to meet the condition on the left square, but then it does not satisfy the condition on the right square.

Sample Input 3

2 2
3
1 1 20
1 2 10
2 1 0

Sample Output 3

No

You have to write -10 into the empty cell to meet condition 2, but then it does not satisfy condition 1.

Sample Input 4

3 3
4
1 1 0
1 3 10
3 1 10
3 3 20

Sample Output 4

Yes

You can write integers as follows.

Sample Input 5

2 2
4
1 1 0
1 2 10
2 1 30
2 2 20

Sample Output 5

No

All cells already contain a integer and condition 2 is not satisfied.

Solution in C (GCC 5.4.1) (judge verdict: Runtime Error)

#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// 内部定数
#define D_SIZE_MAX		100005									// 最大サイズ
#define D_MASS_MAX		100000									// 最大マス数
#define D_TREE_CNT		2										// 木の数
#define D_TNO_ROW		0										// 木の配列番号 - 行
#define D_TNO_COL		1										// 木の配列番号 - 列
#define D_TREE_MAX		D_MASS_MAX * 2							// 木の最大データ数
#define D_TREE_WCNT		2										// 木の方向数
#define D_TREE_LEFT		0										// 木の方向 - 左側
#define D_TREE_RIGHT	1										// 木の方向 - 右側

// 内部構造体 - 木構造
typedef struct Tree {
	int miRow, miCol;											// 行・列
	int miVal;													// 値
	int mi1Height[D_TREE_WCNT];									// 木の高さ
	struct Tree *mzp1Child[D_TREE_WCNT];						// 子
} Tree;

// 内部変数
static FILE *szpFpI;											// 入力
static int siRow, siCol;										// 行・列
static Tree sz2Tree[D_TREE_CNT][D_TREE_MAX];					// 木の実データ
static int si1TCnt[D_TREE_CNT];									// 木の実データ数
static Tree *szp1Top[D_TREE_CNT];								// 先頭の木データ
static int si2DF[D_TREE_CNT][D_SIZE_MAX];						// 差[行列][位置]

// 内部変数 - テスト用
#ifdef D_TEST
	static int siRes;
	static FILE *szpFpA;
	static int siTNo;
#endif

// 内部宣言
int fAddMass(int, int, int);

// １行出力
int
fOutLine(
	char *pcpLine				// <I> １行
)
{
	char lc1Buf[1024];

#ifdef D_TEST
	lc1Buf[0] = '\0';
	fgets(lc1Buf, sizeof(lc1Buf), szpFpA);
	if (strcmp(lc1Buf, pcpLine)) {
		siRes = -1;
	}
#else
	printf("%s", pcpLine);
#endif

	return 0;
}

// 比較関数 - 行昇順 - 列昇順
int
fCmpFncRuCu(
	int piRow1					// <I> 行１
	, int piRow2				// <I> 行２
	, int piCol1				// <I> 列１
	, int piCol2				// <I> 列２
)
{
	if (piRow1 < piRow2) {
		return -1;
	}
	else if (piRow1 > piRow2) {
		return 1;
	}

	if (piCol1 < piCol2) {
		return -1;
	}
	else if (piCol1 > piCol2) {
		return 1;
	}

	return 0;
}

// 比較関数 - 列昇順 - 行昇順
int
fCmpFncCuRu(
	int piRow1					// <I> 行１
	, int piRow2				// <I> 行２
	, int piCol1				// <I> 列１
	, int piCol2				// <I> 列２
)
{
	if (piCol1 < piCol2) {
		return -1;
	}
	else if (piCol1 > piCol2) {
		return 1;
	}

	if (piRow1 < piRow2) {
		return -1;
	}
	else if (piRow1 > piRow2) {
		return 1;
	}

	return 0;
}

// 木データ - クリア
int
fTreeClear(
	int piTNo					// <I> 木の配列番号 0～
)
{
	si1TCnt[piTNo] = 0;											// 木の実データ数
	szp1Top[piTNo] = NULL;										// 先頭の木データ

	return 0;
}

// 木データ - 作成
Tree *
fTreeMake(
	int piTNo					// <I> 木の配列番号 0～
	, int piRow					// <I> 行
	, int piCol					// <I> 列
	, int piVal					// <I> 値
)
{
	// 対象の木データ
	Tree *lzpTree = &(sz2Tree[piTNo][si1TCnt[piTNo]]);
	(si1TCnt[piTNo])++;

	// データセット
	memset(lzpTree, 0, sizeof(Tree));					// 初期化
	lzpTree->miRow = piRow;
	lzpTree->miCol = piCol;
	lzpTree->miVal = piVal;

	return lzpTree;
}

// 木データ - 比較
int
fTreeCmp(
	int piTNo					// <I> 木の配列番号 0～
	, Tree *pzpTree				// <I> 木データ
	, int piRow					// <I> 行
	, int piCol					// <I> 列
)
{
	if (piTNo == D_TNO_ROW) {
		return fCmpFncRuCu(piRow, pzpTree->miRow, piCol, pzpTree->miCol);
	}
	else {
		return fCmpFncCuRu(piRow, pzpTree->miRow, piCol, pzpTree->miCol);
	}
}

// 木データ - 検索
Tree *
fTreeSrh(
	int piTNo					// <I> 木の配列番号 0～
	, int piRow					// <I> 行
	, int piCol					// <I> 列
)
{
	// 先頭の木データ
	Tree *lzpNow = szp1Top[piTNo];

	// 検索
	while (1) {

		// データ有無
		if (lzpNow == NULL) {
			return NULL;
		}

		// 比較
		int liRet = fTreeCmp(piTNo, lzpNow, piRow, piCol);
		if (liRet == 0) {										// 一致
			return lzpNow;
		}

		// 子へ移動
		if (liRet < 0) {										// 左側
			lzpNow = lzpNow->mzp1Child[D_TREE_LEFT];
		}
		else {													// 右側
			lzpNow = lzpNow->mzp1Child[D_TREE_RIGHT];
		}
	}

	return NULL;
}

// 木データ - 高さ取得
int
fTreeGetHeight(
	Tree *pzpTree				// <I> 対象の木情報
)
{
	// データ有無
	if (pzpTree == NULL) {
		return 0;
	}

	if (pzpTree->mi1Height[D_TREE_LEFT] >= pzpTree->mi1Height[D_TREE_RIGHT]) {
		return pzpTree->mi1Height[D_TREE_LEFT] + 1;
	}
	else {
		return pzpTree->mi1Height[D_TREE_RIGHT] + 1;
	}
}

// 木データ - 右回転(親は子[左]の右下へ・子[左]は親の左上へ)
int
fTreeRttR(
	Tree **pzppTree				// <I> 回転対象
)
{
	// 現在の子[左]
	Tree *lzpChild = (*pzppTree)->mzp1Child[D_TREE_LEFT];

	// 右回転
	(*pzppTree)->mzp1Child[D_TREE_LEFT] = lzpChild->mzp1Child[D_TREE_RIGHT];	// 親の左側 = 子[左]の右側
	(*pzppTree)->mi1Height[D_TREE_LEFT] = lzpChild->mi1Height[D_TREE_RIGHT];	// 親の高さ(左) = 子[左]の高さ(右)
	lzpChild->mzp1Child[D_TREE_RIGHT] = *pzppTree;								// 子[左]の右側 = 親
	lzpChild->mi1Height[D_TREE_RIGHT] = fTreeGetHeight(*pzppTree);				// 子[左]の高さ(右) - 親の高さ
	*pzppTree = lzpChild;														// 親 = 子[左]

	return 0;
}

// 木データ - 左回転(親は子[右]の左下へ・子[右]は親の右上へ)
int
fTreeRttL(
	Tree **pzppTree				// <I> 回転対象
)
{
	// 現在の子[右]
	Tree *lzpChild = (*pzppTree)->mzp1Child[D_TREE_RIGHT];

	// 左回転
	(*pzppTree)->mzp1Child[D_TREE_RIGHT] = lzpChild->mzp1Child[D_TREE_LEFT];	// 親の右側 = 子[右]の左側
	(*pzppTree)->mi1Height[D_TREE_RIGHT] = lzpChild->mi1Height[D_TREE_LEFT];	// 親の高さ(右) = 子[右]の高さ(左)
	lzpChild->mzp1Child[D_TREE_LEFT] = *pzppTree;								// 子[右]の左側 = 親
	lzpChild->mi1Height[D_TREE_LEFT] = fTreeGetHeight(*pzppTree);				// 子[右]の高さ(左) - 親の高さ
	*pzppTree = lzpChild;														// 親 = 子[右]

	return 0;
}

// 木データ - 追加・削除の共通処理
// 戻り値：[2]高さの変更あり [1]高さの変更なし
int
fTreeComAddDel(
	Tree **pzppNow				// <I> 現在の木情報
	, int piWay					// <I> 対象の方向
)
{
	// 高さの変更があるかチェック
	int liNew = fTreeGetHeight((*pzppNow)->mzp1Child[piWay]);
	if ((*pzppNow)->mi1Height[piWay] == liNew) {												// 変化なし
		return 1;
	}
	(*pzppNow)->mi1Height[piWay] = liNew;														// 更新

	// 高さが離れている場合、回転
	if ((*pzppNow)->mi1Height[D_TREE_LEFT] - (*pzppNow)->mi1Height[D_TREE_RIGHT] > 1) {			// 左側が高い
		fTreeRttR(pzppNow);																			// 右回転
	}
	else if ((*pzppNow)->mi1Height[D_TREE_RIGHT] - (*pzppNow)->mi1Height[D_TREE_LEFT] > 1) {	// 右側が高い
		fTreeRttL(pzppNow);																			// 左回転
	}

	return 2;
}

// 木データ - 追加
// 戻り値：[2]高さの変更あり [1]高さの変更なし [0]データ数の追加のみ
int
fTreeAdd(
	int piTNo					// <I> 木の配列番号 0～
	, Tree **pzppNow			// <I> 現在の木情報
	, int piRow					// <I> 行
	, int piCol					// <I> 列
	, int piVal					// <I> 値
)
{
	// 作成
	if (*pzppNow == NULL) {
		*pzppNow = fTreeMake(piTNo, piRow, piCol, piVal);
		return 1;
	}

	// 比較
	int liRet = fTreeCmp(piTNo, *pzppNow, piRow, piCol);

	// 一致
	if (liRet == 0) {
		return 0;
	}

	// 方向の判別
	int liWay;
	if (liRet < 0) {																	// 左側
		liWay = D_TREE_LEFT;
	}
	else {																				// 右側
		liWay = D_TREE_RIGHT;
	}

	// 下位へ
	liRet = fTreeAdd(piTNo, &((*pzppNow)->mzp1Child[liWay]), piRow, piCol, piVal);
	if (liRet == 0) {																	// 変更なし
		return 0;
	}

	// 追加・削除の共通処理
	return fTreeComAddDel(pzppNow, liWay);
}

// 差 - セット
int
fSetDF(
	int piRC					// <I> 行・列
	, int piPos					// <I> 位置
	, int piDF					// <I> 差
)
{
	if (si2DF[piRC][piPos] == INT_MAX) {		// 新規
		si2DF[piRC][piPos] = piDF;
	}
	else if (si2DF[piRC][piPos] == piDF) {		// 一致
		return 0;
	}
	else {										// 不一致
		return -1;
	}

	return 0;
}

// 隣接マス - チェック
int
fChkMass(
	int piRC					// <I> 行・列
	, int piRow					// <I> 行
	, int piCol					// <I> 列
	, int piVal					// <I> 値
	, int piWay					// <I> 方向
)
{
	int liRet;

	// 隣接マス・差
	int liRow, liCol, liVal, liDF;
	if (piRC == D_TNO_ROW) {
		liRow = piRow + piWay;
		liCol = piCol;
		if (piWay > 0) {
			liDF = si2DF[D_TNO_ROW][piRow];
		}
		else {
			liDF = si2DF[D_TNO_ROW][liRow];
		}
	}
	else {
		liRow = piRow;
		liCol = piCol + piWay;
		if (piWay > 0) {
			liDF = si2DF[D_TNO_COL][piCol];
		}
		else {
			liDF = si2DF[D_TNO_COL][liCol];
		}
	}

	// 隣接マス - 取得
	Tree *lzpTree;
	while (1) {
		lzpTree = fTreeSrh(piRC, liRow, liCol);
		if (lzpTree != NULL) {
			break;
		}

		// 差 - なし
		if (liDF == INT_MAX) {
			return 0;
		}

		// 隣接マス - 追加
		if (piWay > 0) {
			liVal = piVal + liDF;
		}
		else {
			liVal = piVal - liDF;
		}
		liRet = fAddMass(liRow, liCol, liVal);
		if (liRet != 0) {
			return -1;
		}
	}

	// 差 - セット
	if (piRC == D_TNO_ROW) {
		if (piWay > 0) {
			liRet = fSetDF(piRC, piRow, lzpTree->miVal - piVal);
		}
		else {
			liRet = fSetDF(piRC, liRow, piVal - lzpTree->miVal);
		}
	}
	else {
		if (piWay > 0) {
			liRet = fSetDF(piRC, piCol, lzpTree->miVal - piVal);
		}
		else {
			liRet = fSetDF(piRC, liCol, piVal - lzpTree->miVal);
		}
	}
	if (liRet != 0) {
		return -1;
	}

	return 0;
}

// マス - 追加
int
fAddMass(
	int piRow					// <I> 行
	, int piCol					// <I> 列
	, int piVal					// <I> 値
)
{
	int liRet;

	// 値 - チェック
	if (piVal < 0) {
		return -1;
	}

	// マス - 追加
	fTreeAdd(D_TNO_ROW, &(szp1Top[D_TNO_ROW]), piRow, piCol, piVal);
	fTreeAdd(D_TNO_COL, &(szp1Top[D_TNO_COL]), piRow, piCol, piVal);

	// 隣接マス - チェック
	liRet = fChkMass(D_TNO_ROW, piRow, piCol, piVal, 1);
	if (liRet != 0) {
		return -1;
	}
	liRet = fChkMass(D_TNO_ROW, piRow, piCol, piVal, -1);
	if (liRet != 0) {
		return -1;
	}
	liRet = fChkMass(D_TNO_COL, piRow, piCol, piVal, 1);
	if (liRet != 0) {
		return -1;
	}
	liRet = fChkMass(D_TNO_COL, piRow, piCol, piVal, -1);
	if (liRet != 0) {
		return -1;
	}

	return 0;
}

// 実行メイン
int
fMain(
)
{
	int i, liRet;
	char lc1Buf[1024];

	// 行・列 - 取得
	fgets(lc1Buf, sizeof(lc1Buf), szpFpI);
	sscanf(lc1Buf, "%d%d", &siRow, &siCol);

	// 差 - 初期化
	for (i = 0; i <= siRow; i++) {
		si2DF[D_TNO_ROW][i] = INT_MAX;
	}
	for (i = 0; i <= siCol; i++) {
		si2DF[D_TNO_COL][i] = INT_MAX;
	}

	// マス数 - 取得
	int liMCnt;
	fgets(lc1Buf, sizeof(lc1Buf), szpFpI);
	sscanf(lc1Buf, "%d", &liMCnt);

	// マス - 取得
	for (i = 0; i < liMCnt; i++) {
		int liRow, liCol, liVal;
		fgets(lc1Buf, sizeof(lc1Buf), szpFpI);
		sscanf(lc1Buf, "%d%d%d", &liRow, &liCol, &liVal);

		// マス - 追加
		liRet = fAddMass(liRow, liCol, liVal);
		if (liRet != 0) {
			return -1;
		}
	}

	return 0;
}

// １回実行
int
fOne(
)
{
	int liRet;
	char lc1Buf[1024];

	// データ - 初期化
	fTreeClear(D_TNO_ROW);										// 木 - 行
	fTreeClear(D_TNO_COL);										// 木 - 列

	// 入力 - セット
#ifdef D_TEST
	sprintf(lc1Buf, ".\\Test\\T%d.txt", siTNo);
	szpFpI = fopen(lc1Buf, "r");
	sprintf(lc1Buf, ".\\Test\\A%d.txt", siTNo);
	szpFpA = fopen(lc1Buf, "r");
	siRes = 0;
#else
	szpFpI = stdin;
#endif

	// 実行メイン
	liRet = fMain();

	// 出力
	if (liRet == 0) {
		sprintf(lc1Buf, "Yes\n");
	}
	else {
		sprintf(lc1Buf, "No\n");
	}
	fOutLine(lc1Buf);

	// 残データ有無
#ifdef D_TEST
	lc1Buf[0] = '\0';
	fgets(lc1Buf, sizeof(lc1Buf), szpFpA);
	if (strcmp(lc1Buf, "")) {
		siRes = -1;
	}
#endif

	// テストファイルクローズ
#ifdef D_TEST
	fclose(szpFpI);
	fclose(szpFpA);
#endif

	// テスト結果
#ifdef D_TEST
	if (siRes == 0) {
		printf("OK %d\n", siTNo);
	}
	else {
		printf("NG %d\n", siTNo);
	}
#endif

	return 0;
}

// プログラム開始
int
main()
{

#ifdef D_TEST
	int i;
	for (i = D_TEST_SNO; i <= D_TEST_ENO; i++) {
		siTNo = i;
		fOne();
	}
#else
	fOne();
#endif

	return 0;
}