#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define RFOR(i, a, b) for (int i = (a) - 1; i >= (b); i--)
#define SZ(a) int(a.size())
#define ALL(a) a.begin(), a.end()
#define PB push_back
#define MP make_pair
#define F first
#define S second
typedef long long LL;
typedef vector<int> VI;
typedef pair<int, int> PII;
typedef double db;
const int mod = 998244353;
const int N = 1 << 18;
void updAdd(int& x, int val)
{
x += val;
if (x >= mod)
x -= mod;
}
int add(int a, int b)
{
return a + b < mod ? a + b : a + b - mod;
}
int mult(int a, int b)
{
return (LL)a * b % mod;
}
struct SegTree
{
int t[N];
int lazy[N];
void build(int v, int tl, int tr)
{
t[v] = 0;
lazy[v] = 1;
if (tr == tl + 1)
return;
int tm = (tl + tr) / 2;
build(2 * v + 1, tl, tm);
build(2 * v + 2, tm, tr);
}
void push(int v)
{
if (2 * v < N)
{
FOR(i, 1, 3)
lazy[2 * v + i] = mult(lazy[2 * v + i], lazy[v]);
}
t[v] = mult(t[v], lazy[v]);
lazy[v] = 1;
}
void updAssign(int v, int tl, int tr, int pos, int val)
{
push(v);
if (tr == tl + 1)
{
t[v] = val;
return;
}
int tm = (tl + tr) / 2;
if (pos < tm)
updAssign(2 * v + 1, tl, tm, pos, val);
else
updAssign(2 * v + 2, tm, tr, pos, val);
t[v] = add(t[2 * v + 1], t[2 * v + 2]);
}
void updMult(int v, int tl, int tr, int l, int r)
{
push(v);
if (tr <= l || r <= tl)
return;
if (l <= tl && tr <= r)
{
lazy[v] = 2;
push(v);
return;
}
int tm = (tl + tr) / 2;
updMult(2 * v + 1, tl, tm, l, r);
updMult(2 * v + 2, tm, tr, l, r);
t[v] = add(t[2 * v + 1], t[2 * v + 2]);
}
int query(int v, int tl, int tr, int l, int r)
{
push(v);
if (tr <= l || r <= tl)
return 0;
if (l <= tr && tr <= r)
return t[v];
int tm = (tl + tr) / 2;
return add(query(2 * v + 1, tl, tm, l, r), query(2 * v + 2, tm, tr, l, r));
}
} st[2];
void solve()
{
int n;
cin >> n;
vector<PII> segs[2];
FOR(i, 0, 2)
segs[i] = {{0, 0}};
FOR(i, 0, n)
{
int l, r, c;
cin >> l >> r >> c;
segs[c].PB({r, l});
}
vector<int> dp[2];
FOR(i, 0, 2)
{
sort(ALL(segs[i]));
dp[i].resize(SZ(segs[i]));
dp[i][0] = 1;
st[i].build(0, 0, SZ(dp[i]));
}
int ptr[2] = {1, 1};
int ans = 1;
while (ptr[0] < SZ(dp[0]) || ptr[1] < SZ(dp[1]))
{
int k = ptr[1] < SZ(dp[1]) && (ptr[0] == SZ(dp[0]) || segs[1][ptr[1]] < segs[0][ptr[0]]);
int j = lower_bound(ALL(segs[k ^ 1]), MP(segs[k][ptr[k]].S, 0)) - segs[k ^ 1].begin();
int cur = st[k ^ 1].query(0, 0, SZ(dp[k ^ 1]), 0, j);
st[k].updAssign(0, 0, SZ(dp[k]), ptr[k], cur);
st[k ^ 1].updAssign(0, 0, SZ(dp[k ^ 1]), 0, j);
ptr[k]++;
updAdd(ans, cur);
cerr << k << " " << ptr[k] - 1 << " " << segs[k][ptr[k] - 1].S << " " << segs[k][ptr[k] - 1].F << " " << cur << endl;
}
cout << ans << "\n";
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout << fixed << setprecision(15);
int t;
cin >> t;
while(t--)
solve();
return 0;
}
0 1 1 5 0
1 1 3 6 0
0 2 4 7 1
2
0 1 1 5 0
0 2 3 6 1
1 1 7 9 1
3