// 解き直し.
// https://www.slideshare.net/chokudai/arc044
// C++(GCC 9.2.1)
#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;
using vvi = vector<vi>;
#define repex(i, a, b, c) for(int i = a; i < b; i += c)
#define repx(i, a, b) repex(i, a, b, 1)
#define rep(i, n) repx(i, 0, n)
#define repr(i, a, b) for(int i = a; i >= b; i--)
#define pb push_back
#define a first
#define b second
#define all(x) x.begin(), x.end()
const int INF = 1010101010;
int dpX[101010], dpY[101010];
int main(){
// 1. 入力情報.
int W, H, Q;
scanf("%d %d %d", &W, &H, &Q);
vvi vx(101010), vy(101010);
rep(i, Q){
int t, d, x;
scanf("%d %d %d", &t, &d, &x);
if(!d) vx[t].pb(x);
else vy[t].pb(x);
}
// 2. dp更新.
// ex.
// 7 10 19
// 1 0 1
// 1 0 2
// 1 0 3
// 1 0 4
// 1 0 5
// 1 0 7
// 2 0 2
// 2 0 3
// 2 0 6
// 3 0 1
// 3 0 2
// 3 0 4
// 3 0 7
// 4 0 2
// 4 0 5
// 4 0 6
// 5 0 2
// 5 0 4
// 5 0 7
//
// 解説にあるように, おおよそ, ビームの本数分が更新されるように調整.
// 更新① => 前回ビームが通過した位置で, 今回ビームが通過しない場合は,
// 前回ビームが通過した区間の左右を比較して, dp更新.
// 更新② => 今回ビーム自身 に INF を 割り当てる.
//
// [座標] 1 2 3 4 5 6 7
// [時刻]
// 0 0 0 0 0 0 0 0
//
// 1 (更新①) - - - - - - - ※ - は 更新対象外(前回からの値を引き継ぐ, 以下略)
// (更新②) INF INF INF INF INF 0 INF
//
// 2 (更新①) 5 - - 2 1 - 1
// (更新②) 5 INF INF 2 1 INF 1
//
// 3 (更新①) - - 3 - - 2 -
// (更新②) INF INF 3 INF 1 2 INF
//
// 4 (更新①) 5 - - 2 - - 3
// (更新②) 5 INF 3 2 INF INF 3
//
// 5 (更新①) - - - - 3 4 -
// (更新②) 5 INF 3 INF 3 4 INF
//
// -> 以上から, 最初(座標 6) => 時刻 1.5(座標 5) => 時刻 1.5(座標 4) => 時刻 2.5(座標 3)
// に 移動すると, 移動回数 3 が 最小と分かる.
//
// 2-1. 縦.
set<int> xBef, xCur;
map<int, int> mx;
vi xSections;
rep(i, 101010){
// 更新対象.
if(!vx[i].size()) continue;
for(auto &p : vx[i]) xCur.insert(p);
for(auto &p : xBef){
if(!xCur.count(p)){
// 区間[l, r].
int at = upper_bound(all(xSections), p) - xSections.begin();
if(at) --at;
int l = xSections[at];
int r = mx[l];
if(p >= l && p <= r){
if(l > 1) dpX[p] = min(dpX[p], dpX[l - 1] + p - (l - 1));
if(r < W) dpX[p] = min(dpX[p], dpX[r + 1] + (r + 1) - p);
}
}
}
// ビーム反映.
for(auto &p : vx[i]) dpX[p] = INF;
// 区間作成.
vx[i].pb(INF); // 番兵.
mx.clear();
xSections.clear();
int s = 0;
for(auto &p : xCur){
if(!mx.count(s) || p - mx[s] != 1){
s = p;
mx[s] = p;
continue;
}
++mx[s];
}
for(auto &p : mx) xSections.pb(p.a);
// 前回分更新.
xBef = xCur;
xCur.clear();
}
// 2-2. 横.
set<int> yBef, yCur;
map<int, int> my;
vi ySections;
rep(i, 101010){
// 更新対象.
if(!vy[i].size()) continue;
for(auto &p : vy[i]) yCur.insert(p);
for(auto &p : yBef){
if(!yCur.count(p)){
// 区間[l, r].
int at = upper_bound(all(ySections), p) - ySections.begin();
if(at) --at;
int l = ySections[at];
int r = my[l];
if(p >= l && p <= r){
if(l > 1) dpY[p] = min(dpY[p], dpY[l - 1] + p - (l - 1));
if(r < H) dpY[p] = min(dpY[p], dpY[r + 1] + (r + 1) - p);
}
}
}
// ビーム反映.
for(auto &p : vy[i]) dpY[p] = INF;
// 区間作成.
vy[i].pb(INF); // 番兵.
my.clear();
ySections.clear();
int s = 0;
for(auto &p : yCur){
if(!my.count(s) || p - my[s] != 1){
s = p;
my[s] = p;
continue;
}
++my[s];
}
for(auto &p : my) ySections.pb(p.a);
// 前回分更新.
yBef = yCur;
yCur.clear();
}
// 3. 移動回数の最小値は?
// 3-1. 縦.
int xMin = INF;
repx(i, 1, W + 1) xMin = min(xMin, dpX[i]);
// 3-2. 横.
int yMin = INF;
repx(i, 1, H + 1) yMin = min(yMin, dpY[i]);
// 4. 出力.
int ans = xMin + yMin;
printf("%d\n", (ans < INF) ? ans : -1);
return 0;
}