#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <chrono>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <vector>
using namespace std;
#define i64 long long
#define all(x) begin(x), end(x)
#define sz(x) (int) (x).size()
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int BUF_SZ = 1 << 15;
inline namespace Input {
char buf[BUF_SZ];int pos;int len;
char next_char() {
if (pos == len) {pos = 0;
len = (int)fread(buf, 1, BUF_SZ, stdin);
if (!len) { return EOF; }}
return buf[pos++];}
int read_int() {
int x;char ch;int sgn = 1;
while (!isdigit(ch = next_char())) {
if (ch == '-') { sgn *= -1; }}
x = ch - '0';
while (isdigit(ch = next_char())) { x = x * 10 + (ch - '0'); }
return x * sgn;}
}
inline namespace Output {
char buf[BUF_SZ];int pos;
void flush_out() {fwrite(buf, 1, pos, stdout);pos = 0;}
void write_char(char c) {
if (pos == BUF_SZ) { flush_out(); }
buf[pos++] = c;}
void write_int(int x) {
static char num_buf[100];
if (x < 0) {write_char('-');x *= -1;}
int len = 0;
for (; x >= 10; x /= 10) { num_buf[len++] = (char)('0' + (x % 10)); }
write_char((char)('0' + x));
while (len) { write_char(num_buf[--len]); }
}
void init_output() { assert(atexit(flush_out) == 0); }
}
const i64 mod = 998244353;
namespace segtree {
const int LIM = 5e6;
const int DL = 0, DR = 1e5+5;
i64 cf[LIM], sv[LIM], ss[LIM];
int lc[LIM], rc[LIM], cc[LIM];
int rt[7*LIM], rv[7*LIM];
i64 rx[7*LIM];
int nxt = 1, rxt = -1;
int rmx=0;
void reset() {nxt=1,rxt=-1;}
int create() {
if (nxt >= LIM) assert(0);
cf[nxt]=lc[nxt]=rc[nxt]=sv[nxt]=ss[nxt]=0,cc[nxt]=1;
return nxt++;
}
void pull(int v) {
// cout<<v<<endl;
sv[v] = (cf[v]*ss[v])%mod;
if (lc[v]) sv[v]+=sv[lc[v]];
if (rc[v]) sv[v]+=sv[rc[v]];
sv[v] %= mod;
cc[v] = 1; //cleared
if (lc[v] && !cc[lc[v]]) {cc[v]=0;}
if (rc[v] && !cc[rc[v]]) {cc[v]=0;}
if (cf[v]) {cc[v]=0;}
}
void buf() {rt[++rxt]=0;}
void f(int v, int x) {
cf[v] = ((cf[v]+x)%mod+mod)%mod;
rmx=max(rmx,rxt);
rt[++rxt] = 1;
rv[rxt] = v; rx[rxt] = x;
pull(v);
}
void push(int v) {
if (!lc[v]) lc[v] = create();
if (!rc[v]) rc[v] = create();
f(lc[v],cf[v]);
f(rc[v],cf[v]);
f(v,-cf[v]);
}
void range_add_coef(int ql, int qr, int qx, int cp, int cl, int cr) {
if (ql > cr || qr < cl) return;
f(cp,0);
if (ql <= cl && cr <= qr) {
f(cp,qx);
} else {
if (!lc[cp]) lc[cp] = create();
if (!rc[cp]) rc[cp] = create();
range_add_coef(ql,qr,qx,lc[cp],cl,(cl+cr)/2);
range_add_coef(ql,qr,qx,rc[cp],(cl+cr)/2+1,cr);
pull(cp);
}
}
void range_add_coef(int ql, int qr, int qx, int cp) {
// cout<<"radd\n";
buf();
range_add_coef(ql,qr,qx,cp,DL,DR);
}
void clear(int ql, int qr, int cp, int cl, int cr) {
if (ql > cr || qr < cl) return;
pull(cp);
if (cc[cp]) return;
f(cp,0);
if (ql <= cl && cr <= qr) {
f(cp,-cf[cp]);
} else {push(cp);}
if (lc[cp]) clear(ql,qr,lc[cp],cl,(cl+cr)/2);
if (rc[cp]) clear(ql,qr,rc[cp],(cl+cr)/2+1,cr);
pull(cp);
}
void clear(int ql, int qr, int cp) {
// cout<<"clear\n";
buf();
clear(ql,qr,cp,DL,DR);
}
void set_dp(int qi, int qx, int cp, int cl=DL, int cr=DR) {
ss[cp] += qx;
f(cp,0);
if (cl != cr) {
if (qi <= (cl+cr)/2) {
if (!lc[cp]) lc[cp] = create();
set_dp(qi,qx,lc[cp],cl,(cl+cr)/2);
} else {
if (!rc[cp]) rc[cp] = create();
set_dp(qi,qx,rc[cp],(cl+cr)/2+1,cr);
}
pull(cp);
}
pull(cp);
}
int merge(int r1, int r2) {
if (!r1) return r2;
if (!r2) return r1;
rt[++rxt] = 4, rv[rxt] = r1, rx[rxt] = r2;
f(r1,cf[r2]);
rmx=max(rmx,rxt);
rt[++rxt] = 2, rv[rxt] = r1, rx[rxt] = lc[r1];
rmx=max(rmx,rxt);
rt[++rxt] = 3, rv[rxt] = r1, rx[rxt] = rc[r1];
lc[r1] = merge(lc[r1],lc[r2]);
rc[r1] = merge(rc[r1],rc[r2]);
pull(r1);
return r1;
}
int MERGE(int r1, int r2) {
// cout<<"merge\n";
buf();
return merge(r1,r2);
}
void rollback(int t=0) {
// cout<<"rollback "<<t<<"\n";
assert(rxt>=0);
while (rt[rxt]) {
if (rt[rxt]==1) {
cf[rv[rxt]] -= rx[rxt];
} else if (rt[rxt]==2) {
lc[rv[rxt]] = rx[rxt];
} else if (rt[rxt]==3) {
rc[rv[rxt]] = rx[rxt];
} else if (rt[rxt]==4) {
ss[rx[rxt]] = ss[rv[rxt]];
pull(rx[rxt]);
} else {assert(0);}
pull(rv[rxt]); rxt--;
}
rxt--;
}
int get(int r) {return sv[r];}
void pull_all() {
for (int i=nxt-1; i>0; i--) {
pull(i);
}
}
}
const int mxn=1e5+5;
int n;
int p[mxn],l[mxn],r[mxn],h[mxn],d[mxn];
int sgt[mxn];
vector<int> adj[mxn];
int dp[mxn];
void dfs(int v) {
for (int u : adj[v]) {
dfs(u);
}
for (int u : adj[v]) {
sgt[v] = segtree::MERGE(sgt[v],sgt[u]);
}
int lodep = d[v]-r[v];
int hidep = d[v]-l[v];
segtree::range_add_coef(lodep,hidep,1,sgt[v]);
int bad = d[v]-h[v];
segtree::clear(bad,segtree::DR,sgt[v]);
}
void undo(int v) {
if (v) {
dp[v] = segtree::get(sgt[v]);
} else {
dp[v] = 1;
}
segtree::rollback(1);
segtree::rollback(2);
for (int u : adj[v]) {
segtree::rollback(3);
}
reverse(all(adj[v]));
for (int u : adj[v]) {
segtree::set_dp(d[v],dp[v],sgt[u]);
undo(u);
}
}
void solve() {
segtree::reset();
n=read_int();
for (int i=0; i<n; i++) adj[i].clear();
for (int i=1; i<n; i++) {
p[i]=read_int(),l[i]=read_int(),r[i]=read_int(),h[i]=read_int();
--p[i]; adj[p[i]].push_back(i);
d[i] = d[p[i]]+1;
}
for (int i=0; i<n; i++) {
sgt[i] = segtree::create();
}
dfs(0);
undo(0);
for (int i=1; i<n; i++) {
write_int(dp[i]);
write_char(' ');
}
write_char('\n');
}
signed main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
init_output();
int c=read_int();
int t=read_int();
while (t--) {
solve();
}
return 0;
}