/**
 * Đầu vào: Hai đa thức có độ dài n, m. 1 <= n, m <= 1e6-1 thể hiện bậc cao nhất của đa thức là n+1, m+1
 Hệ số hạng tử nằm trong khoảng [-1e9; 1e9]
 
 * Đầu ra: Đa thức kết quả ở dạng đầy đủ có giá trị trong khoảng [-1e24; 1e24], không mod
 **/
 
#include <bits/stdc++.h>
#define up(i,a,b) for (int i = (int)a; i <= (int)b; i++)
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using u32 = uint32_t;
using u64 = uint64_t;
using i128 = __int128;
using u128 = unsigned __int128;

// ================= Fast IO (USACO style) =================
const int BUF_SZ = 1 << 20;

inline namespace Input {
    char buf[BUF_SZ];
    int pos, len;
    inline char next_char() {
        if (pos == len) {
            pos = 0;
            len = (int)fread(buf, 1, BUF_SZ, stdin);
            if (!len) return EOF;
        }
        return buf[pos++];
    }
    inline i64 read_int() {
        char ch;
        while ((ch = next_char()) != '-' && !isdigit(ch));
        bool neg = false;
        if (ch == '-') { neg = true; ch = next_char(); }
        i64 x = ch - '0';
        while (isdigit(ch = next_char())) x = x * 10 + (ch - '0');
        return neg ? -x : x;
    }
}

inline namespace Output {
    char buf[BUF_SZ];
    int pos;
    inline void flush_out() {
        fwrite(buf, 1, pos, stdout);
        pos = 0;
    }
    inline void write_char(char c) {
        if (pos == BUF_SZ) flush_out();
        buf[pos++] = c;
    }
    inline void write_int(i64 x) {
        static char num_buf[24];
        if (x < 0) { write_char('-'); x = -x; }
        int len = 0;
        do { num_buf[len++] = (char)('0' + (x % 10)); x /= 10; } while (x);
        while (len) write_char(num_buf[--len]);
    }
    // in i128 co dau: tach 1 lan theo 10^18 (1 phep chia 128-bit), phan con lai dung u64
    inline void write_i128(i128 x) {
        if (pos + 48 > BUF_SZ) flush_out();          // dam bao du cho (dau + <=39 chu so)
        u128 ux;
        if (x < 0) { buf[pos++] = '-'; ux = (u128)0 - (u128)x; } else ux = (u128)x;
        const u64 E18 = 1000000000000000000ULL;
        u64 hi = (u64)(ux / E18);
        u64 lo = (u64)(ux - (u128)hi * E18);
        char t[24];
        if (hi) {
            // hi co the dai toi 21 chu so neu |x| ~ 1e39; voi bai nay hi < 4e7
            int l = 0;
            do { t[l++] = (char)('0' + hi % 10); hi /= 10; } while (hi);
            while (l) buf[pos++] = t[--l];
            for (int d = 17; d >= 0; d--) { buf[pos + d] = (char)('0' + lo % 10); lo /= 10; }
            pos += 18;                                // lo dem du 18 chu so
        } else {
            int l = 0;
            do { t[l++] = (char)('0' + lo % 10); lo /= 10; } while (lo);
            while (l) buf[pos++] = t[--l];
        }
    }
    void init_output() { int r = atexit(flush_out); (void)r; }   // khong dung assert: -DNDEBUG se xoa mat atexit
}
// =========================================================

// 3 so nguyen to NTT-friendly chuan, cung primitive root g = 3 (deu < 2^31)
const u32 P1 = 998244353;   // 119*2^23+1
const u32 P2 = 167772161;   // 5*2^25+1
const u32 P3 = 469762049;   // 7*2^26+1
const u32 R  = 3;
const i128 M = (i128)P1 * P2 * P3;
const int MAXN = 1 << 21;   // n+m+1 <= 2e6+1 <= 2^21

u64 power_plain(u64 a, u64 e, u64 mod){
    a %= mod;
    u64 res = 1;
    while (e){
        if (e & 1) res = res * a % mod;
        a = a * a % mod;
        e >>= 1;
    }
    return res;
}

// ================== MONTGOMERY (R = 2^32) ==================
struct Montgomery32 {
    u32 mod, inv_mod, r2;
    void set_mod(u32 m){
        mod = m;
        inv_mod = 1;
        for (int i = 0; i < 5; i++) inv_mod *= 2 - mod * inv_mod;
        u64 r = ((u64)1 << 32) % mod;
        r2 = (u32)(r * r % mod);
    }
    // REDC: 0 <= x < mod * 2^32
    u32 reduce(u64 x) const {
        u32 q = (u32)x * inv_mod;
        u64 m = (u64)q * mod;
        u32 y = (u32)((x - m) >> 32);
        return (y >> 31) ? y + mod : y;
    }
    u32 to_mont(u32 a)    const { return reduce((u64)a * r2); }
    u32 from_mont(u32 a)  const { return reduce((u64)a); }
    u32 mul(u32 a, u32 b) const { return reduce((u64)a * b); }
    u32 add(u32 a, u32 b) const { u32 s = a + b; return s >= mod ? s - mod : s; }
    u32 sub(u32 a, u32 b) const { return a >= b ? a - b : a + mod - b; }
};
// =============================================================

// Mot bo NTT cho 1 modulo: mt + bang root/root_inv (dang Montgomery)
struct NTT {
    Montgomery32 mt;
    u32 mod;
    vector<u32> root, root_inv;

    void init(u32 p, u32 g, int n){
        mod = p;
        mt.set_mod(p);
        root.resize(n); root_inv.resize(n);
        root[1] = root_inv[1] = mt.to_mont(1);
        u32 g_inv = (u32)power_plain(g, p - 2, p);
        for (int k = 2; k * 2 <= n; k <<= 1){
            u32 w_mont     = mt.to_mont((u32)power_plain(g,     (p - 1) / (2 * k), p));
            u32 w_inv_mont = mt.to_mont((u32)power_plain(g_inv, (p - 1) / (2 * k), p));
            for (int j = k / 2; j < k; j++){
                root[j * 2]         = root[j];
                root[j * 2 + 1]     = mt.mul(root[j], w_mont);
                root_inv[j * 2]     = root_inv[j];
                root_inv[j * 2 + 1] = mt.mul(root_inv[j], w_inv_mont);
            }
        }
    }

    // DIF (Gentleman-Sande): vao tu nhien -> ra bit-reversed
    void forward(vector<u32>& a) const {
        int n = a.size();
        for (int len = n; len >= 2; len >>= 1){
            int half = len / 2;
            for (int i = 0; i < n; i += len){
                for (int j = 0; j < half; j++){
                    u32 w = root[half + j];
                    u32 u = a[i + j], v = a[i + j + half];
                    a[i + j]        = mt.add(u, v);
                    a[i + j + half] = mt.mul(mt.sub(u, v), w);
                }
            }
        }
    }

    // DIT (Cooley-Tukey): vao bit-reversed -> ra tu nhien
    void inverse(vector<u32>& a) const {
        int n = a.size();
        for (int len = 2; len <= n; len <<= 1){
            int half = len / 2;
            for (int i = 0; i < n; i += len){
                for (int j = 0; j < half; j++){
                    u32 w = root_inv[half + j];
                    u32 u = a[i + j];
                    u32 v = mt.mul(a[i + j + half], w);
                    a[i + j]        = mt.add(u, v);
                    a[i + j + half] = mt.sub(u, v);
                }
            }
        }
        u32 n_inv = mt.to_mont((u32)power_plain(n, mod - 2, mod));
        for (auto& x : a) x = mt.mul(x, n_inv);
    }

    // tra ve he so tich modulo `mod`, o mien thuong (da from_mont)
    vector<u32> multiply(const vector<i32>& a, const vector<i32>& b, int bound) const {
        vector<u32> A(bound), B(bound);
        // sửa multiply: đưa về [0, mod) đúng cách
        up(i, 0, (int)a.size()-1){ i64 v = a[i] % (i64)mod; if (v < 0) v += mod; A[i] = mt.to_mont((u32)v); }
        up(i, 0, (int)b.size()-1){ i64 v = b[i] % (i64)mod; if (v < 0) v += mod; B[i] = mt.to_mont((u32)v); }
        forward(A);
        forward(B);
        up(i, 0, bound - 1) A[i] = mt.mul(A[i], B[i]);
        inverse(A);
        for (auto& x : A) x = mt.from_mont(x);
        return A;
    }
};

NTT ntt1, ntt2, ntt3;
u32 inv_P1_mod_P2, inv_P1P2_mod_P3;

// ================= Garner CRT: 3 modulus =================
// x = r1 + P1*t2 + P1*P2*t3, tra ve gia tri co dau (|x| < M/2)
i128 garner3(u32 r1, u32 r2, u32 r3){
    // ghep (r1 mod P1) va (r2 mod P2): t2 = (r2 - r1) * P1^-1 mod P2
    u64 t2 = (u64)(((i64)r2 - (i64)r1) % (i64)P2 + P2) % P2 * inv_P1_mod_P2 % P2;
    u64 x12 = (u64)r1 + (u64)P1 * t2;                    // < P1*P2 ~ 1.7e17
    // ghep x12 (mod P1*P2) voi (r3 mod P3): t3 = (r3 - x12) * (P1*P2)^-1 mod P3
    u64 t3 = (u64)(((i64)r3 - (i64)(x12 % P3)) % (i64)P3 + P3) % P3 * inv_P1P2_mod_P3 % P3;
    i128 x = (i128)x12 + (i128)P1 * P2 * t3;
    if (x > M / 2) x -= M;
    return x;
}

void solve(){
    int n = (int)read_int(), m = (int)read_int();
    vector<i32> a(n + 1), b(m + 1);
    for (auto& x : a) x = (i32)read_int();
    for (auto& x : b) x = (i32)read_int();

    int need = (int)a.size() + (int)b.size() - 1;
    int bound = 1;
    while (bound < need) bound <<= 1;

    vector<u32> r1 = ntt1.multiply(a, b, bound);
    vector<u32> r2 = ntt2.multiply(a, b, bound);
    vector<u32> r3 = ntt3.multiply(a, b, bound);

    up(i, 0, need - 1){
        write_i128(garner3(r1[i], r2[i], r3[i]));
        write_char(i == need - 1 ? '\n' : ' ');
    }
}

signed main(){
    init_output();
    #define Task "A"
    if (fopen(Task".inp", "r")){
        freopen(Task".inp", "r", stdin);
        freopen(Task".out", "w", stdout);
    }

    ntt1.init(P1, R, MAXN);
    ntt2.init(P2, R, MAXN);
    ntt3.init(P3, R, MAXN);
    inv_P1_mod_P2   = (u32)power_plain(P1 % P2, P2 - 2, P2);
    inv_P1P2_mod_P3 = (u32)power_plain((u64)P1 * P2 % P3, P3 - 2, P3);

    int tt = (int)read_int();
    while (tt--) solve();
}
