Alice's potion making professor gave the following assignment to his students: brew a potion using $$$n$$$ ingredients, such that the proportion of ingredient $$$i$$$ in the final potion is $$$r_i > 0$$$ (and $$$r_1 + r_2 + \cdots + r_n = 1$$$).He forgot the recipe, and now all he remembers is a set of $$$n-1$$$ facts of the form, "ingredients $$$i$$$ and $$$j$$$ should have a ratio of $$$x$$$ to $$$y$$$" (i.e., if $$$a_i$$$ and $$$a_j$$$ are the amounts of ingredient $$$i$$$ and $$$j$$$ in the potion respectively, then it must hold $$$a_i/a_j = x/y$$$), where $$$x$$$ and $$$y$$$ are positive integers. However, it is guaranteed that the set of facts he remembers is sufficient to uniquely determine the original values $$$r_i$$$.He decided that he will allow the students to pass the class as long as they submit a potion which satisfies all of the $$$n-1$$$ requirements (there may be many such satisfactory potions), and contains a positive integer amount of each ingredient.Find the minimum total amount of ingredients needed to make a potion which passes the class. As the result can be very large, you should print the answer modulo $$$998\,244\,353$$$.

The first line contains a single integer $$$t$$$ ($$$1 \le t \le 10^4$$$) — the number of test cases. The first line of each test case contains a single integer $$$n$$$ ($$$2 \le n \le 2 \cdot 10^5$$$). Each of the next $$$n-1$$$ lines contains four integers $$$i, j, x, y$$$ ($$$1 \le i, j \le n$$$, $$$i\not=j$$$, $$$1\le x, y \le n$$$) — ingredients $$$i$$$ and $$$j$$$ should have a ratio of $$$x$$$ to $$$y$$$. It is guaranteed that the set of facts is sufficient to uniquely determine the original values $$$r_i$$$. It is also guaranteed that the sum of $$$n$$$ for all test cases does not exceed $$$2 \cdot 10^5$$$.

For each test case, print the minimum total amount of ingredients needed to make a potion which passes the class, modulo $$$998\,244\,353$$$.

NoteIn the first test case, the minimum total amount of ingredients is $$$69$$$. In fact, the amounts of ingredients $$$1, 2, 3, 4$$$ of a valid potion are $$$16, 12, 9, 32$$$, respectively. The potion is valid because   Ingredients $$$3$$$ and $$$2$$$ have a ratio of $$$9 : 12 = 3 : 4$$$;  Ingredients $$$1$$$ and $$$2$$$ have a ratio of $$$16 : 12 = 4 : 3$$$;  Ingredients $$$1$$$ and $$$4$$$ have a ratio of $$$16 : 32 = 2 : 4$$$. In the second test case, the amounts of ingredients $$$1, 2, 3, 4, 5, 6, 7, 8$$$ in the potion that minimizes the total amount of ingredients are $$$60, 60, 24, 48, 32, 60, 45, 30$$$.

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
async function solve(n, a) {
  function getPrimes(n) {
    const nums = new Array(n + 1).fill(1);
    nums[0] = nums[1] = 0;
    const primes = [];
    const minp = [];
    for (let i = 2; i <= n; i++) {
      if (nums[i]) {
        primes.push(i);
        minp[i] = i;
      }
      for (let num of primes) {
        const j = num * i;
        if (j > n) break;
        minp[j] = num;
        nums[j] = 0;
        if (i % num === 0) break;
      }
    }
    const res = Array.from({
      length: n + 1
    }, () => new Map());
    for (let i = 1; i <= n; i++) {
      for (let j = i; j > 1; j /= minp[j]) {
        var _res$i$get;
        res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
      }
    }
    return res;
  }
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  const g = Array.from({
    length: n
  }, () => []);
  let idx = 0;
  const add = (i, j, x, y) => {
    g[i].push(j);
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    async function helper(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = async u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        await helper(y, -1);
        await helper(x, 1);
        await dfs(v);
        await helper(y, 1);
        await helper(x, -1);
      }
    };
    await dfs(0);
    let num = 1;
    for (let i = 2; i <= n; i++) {
      if (max[i]) num = mul(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  console.log((ori.reduce((a, b) => a + b, 0) % MOD).toString());
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function power(a, b) {
  let res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  try {
    let t = Number(await read());
    let res = [];
    while (t--) {
      const n = Number(await read());
      const b = [];
      let tmp = n - 1;
      while (tmp--) {
        const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
        b.push([i, j, x, y]);
      }
      res.push(await solve(n, b));
    }
  } catch (error) {
    console.log(error);
  }
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  function getPrimes(n) {
    const nums = new Array(n + 1).fill(1);
    nums[0] = nums[1] = 0;
    const primes = [];
    const minp = [];
    for (let i = 2; i <= n; i++) {
      if (nums[i]) {
        primes.push(i);
        minp[i] = i;
      }
      for (let num of primes) {
        const j = num * i;
        if (j > n) break;
        minp[j] = num;
        nums[j] = 0;
        if (i % num === 0) break;
      }
    }
    const res = Array.from({
      length: n + 1
    }, () => new Map());
    for (let i = 1; i <= n; i++) {
      for (let j = i; j > 1; j /= minp[j]) {
        var _res$i$get;
        res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
      }
    }
    return res;
  }
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  const g = Array.from({
    length: n
  }, () => []);
  let idx = 0;
  const add = (i, j, x, y) => {
    g[i].push(j);
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function f(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const helper = fn => {
      const done = () => {};
      const dfs = (...args) => {
        const callStack = [[done, args]];
        while (callStack.length) {
          let curCall = callStack[callStack.length - 1];
          while (((_curCall = curCall) === null || _curCall === void 0 ? void 0 : _curCall.length) === 1) {
            var _curCall;
            const after = curCall.pop();
            after();
            callStack.pop();
            curCall = callStack[callStack.length - 1];
            if (curCall && curCall.length > 1) curCall.pop();
          }
          if (!curCall) break;
          const args = curCall[curCall.length - 1];
          const [before, inside, after] = fn(...args);
          before();
          let nextCall = inside(...args);
          callStack.push([after, ...nextCall]);
        }
      };
      return dfs;
    };
    const dfs = helper((u, x, y) => {
      const before = () => {
        st[u] = 1;
        f(y, -1);
        f(x, 1);
      };
      const inside = () => {
        let res = [];
        for (let i = h[u]; i !== -1; i = ne[i]) {
          const v = e[i];
          if (st[v]) continue;
          const [x, y] = w[i];
          res.push([v, x, y]);
        }
        return res;
      };
      const after = () => {
        f(y, 1);
        f(x, -1);
      };
      return [before, inside, after];
    });
    dfs(0, 0, 0);
    let num = 1;
    for (let i = 2; i <= n; i++) {
      if (max[i]) num = mul(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  console.log((ori.reduce((a, b) => a + b, 0) % MOD).toString());
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function power(a, b) {
  let res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  try {
    let t = Number(await read());
    let res = [];
    while (t--) {
      const n = Number(await read());
      const b = [];
      let tmp = n - 1;
      while (tmp--) {
        const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
        b.push([i, j, x, y]);
      }
      res.push(solve(n, b));
    }
  } catch (error) {
    console.log(error);
  }
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  function getPrimes(n) {
    const nums = new Array(n + 1).fill(1);
    nums[0] = nums[1] = 0;
    const primes = [];
    const minp = [];
    for (let i = 2; i <= n; i++) {
      if (nums[i]) {
        primes.push(i);
        minp[i] = i;
      }
      for (let num of primes) {
        const j = num * i;
        if (j > n) break;
        minp[j] = num;
        nums[j] = 0;
        if (i % num === 0) break;
      }
    }
    const res = Array.from({
      length: n + 1
    }, () => new Map());
    for (let i = 1; i <= n; i++) {
      for (let j = i; j > 1; j /= minp[j]) {
        var _res$i$get;
        res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
      }
    }
    return res;
  }
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  const g = Array.from({
    length: n
  }, () => []);
  let idx = 0;
  const add = (i, j, x, y) => {
    g[i].push(j);
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function f(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const helper = fn => {
      const done = () => {};
      const dfs = (...args) => {
        const callStack = [[[done, []], args]];
        while (callStack.length) {
          let curCall = callStack[callStack.length - 1];
          while (((_curCall = curCall) === null || _curCall === void 0 ? void 0 : _curCall.length) === 1) {
            var _curCall;
            const [after, args] = curCall.pop();
            after();
            callStack.pop();
            curCall = callStack[callStack.length - 1];
            if (curCall && curCall.length > 1) curCall.pop();
          }
          if (!curCall) break;
          const args = curCall[curCall.length - 1];
          const [before, inside, after] = fn(...args);
          before();
          let nextCall = inside(...args);
          callStack.push([[after, args], ...nextCall]);
        }
      };
      return dfs;
    };
    const dfs = helper((u, x, y) => {
      const before = () => {
        st[u] = 1;
        f(y, -1);
        f(x, 1);
      };
      const inside = () => {
        let res = [];
        for (let i = h[u]; i !== -1; i = ne[i]) {
          const v = e[i];
          if (st[v]) continue;
          const [x, y] = w[i];
          res.push([v, x, y]);
        }
        return res;
      };
      const after = () => {
        f(y, 1);
        f(x, -1);
      };
      return [before, inside, after];
    });
    dfs(0, 0, 0);
    let num = 1;
    for (let i = 2; i <= n; i++) {
      if (max[i]) num = mul(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  console.log((ori.reduce((a, b) => a + b, 0) % MOD).toString());
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function power(a, b) {
  let res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  try {
    let t = Number(await read());
    let res = [];
    while (t--) {
      const n = Number(await read());
      const b = [];
      let tmp = n - 1;
      while (tmp--) {
        const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
        b.push([i, j, x, y]);
      }
      res.push(solve(n, b));
    }
  } catch (error) {
    console.log(error);
  }
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  function getPrimes(n) {
    const nums = new Array(n + 1).fill(1);
    nums[0] = nums[1] = 0;
    const primes = [];
    const minp = [];
    for (let i = 2; i <= n; i++) {
      if (nums[i]) {
        primes.push(i);
        minp[i] = i;
      }
      for (let num of primes) {
        const j = num * i;
        if (j > n) break;
        minp[j] = num;
        nums[j] = 0;
        if (i % num === 0) break;
      }
    }
    const res = Array.from({
      length: n + 1
    }, () => new Map());
    for (let i = 1; i <= n; i++) {
      for (let j = i; j > 1; j /= minp[j]) {
        var _res$i$get;
        res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
      }
    }
    return res;
  }
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  const g = Array.from({
    length: n
  }, () => []);
  let idx = 0;
  const add = (i, j, x, y) => {
    g[i].push(j);
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function f(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const helper = fn => {
      const done = () => {};
      const dfs = (...args) => {
        const callStack = [[[done, []], args]];
        while (callStack.length) {
          let curCall = callStack[callStack.length - 1];
          while (((_curCall = curCall) === null || _curCall === void 0 ? void 0 : _curCall.length) === 1) {
            var _curCall;
            const [after, args] = curCall.pop();
            after(...args);
            callStack.pop();
            curCall = callStack[callStack.length - 1];
            if (curCall && curCall.length > 1) curCall.pop();
          }
          if (!curCall) break;
          const args = curCall[curCall.length - 1];
          const [before, inside, after] = fn(...args);
          before(...args);
          let nextCall = inside(...args);
          callStack.push([[after, args], ...nextCall]);
        }
      };
      return dfs;
    };
    const dfs = helper((u, x, y) => {
      const before = () => {
        st[u] = 1;
        f(y, -1);
        f(x, 1);
      };
      const inside = () => {
        let res = [];
        for (let i = h[u]; i !== -1; i = ne[i]) {
          const v = e[i];
          if (st[v]) continue;
          const [x, y] = w[i];
          res.push([v, x, y]);
        }
        return res;
      };
      const after = () => {
        f(y, 1);
        f(x, -1);
      };
      return [before, inside, after];
    });
    dfs(0, 0, 0);
    let num = 1;
    for (let i = 2; i <= n; i++) {
      if (max[i]) num = mul(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  console.log((ori.reduce((a, b) => a + b, 0) % MOD).toString());
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function power(a, b) {
  let res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  try {
    let t = Number(await read());
    let res = [];
    while (t--) {
      const n = Number(await read());
      const b = [];
      let tmp = n - 1;
      while (tmp--) {
        const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
        b.push([i, j, x, y]);
      }
      res.push(solve(n, b));
    }
  } catch (error) {
    console.log(error);
  }
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  function getPrimes(n) {
    const nums = new Array(n + 1).fill(1);
    nums[0] = nums[1] = 0;
    const primes = [];
    const minp = [];
    for (let i = 2; i <= n; i++) {
      if (nums[i]) {
        primes.push(i);
        minp[i] = i;
      }
      for (let num of primes) {
        const j = num * i;
        if (j > n) break;
        minp[j] = num;
        nums[j] = 0;
        if (i % num === 0) break;
      }
    }
    const res = Array.from({
      length: n + 1
    }, () => new Map());
    for (let i = 1; i <= n; i++) {
      for (let j = i; j > 1; j /= minp[j]) {
        var _res$i$get;
        res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
      }
    }
    return res;
  }
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  const g = Array.from({
    length: n
  }, () => []);
  let idx = 0;
  const add = (i, j, x, y) => {
    g[i].push(j);
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function f(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const helper = fn => {
      const done = () => {};
      const dfs = (...args) => {
        const callStack = [[[done, []], args]];
        while (callStack.length) {
          let curCall = callStack[callStack.length - 1];
          while (((_curCall = curCall) === null || _curCall === void 0 ? void 0 : _curCall.length) === 1) {
            var _curCall;
            const [after, args] = curCall.pop();
            after(...args);
            callStack.pop();
            curCall = callStack[callStack.length - 1];
            if (curCall && curCall.length > 1) curCall.pop();
          }
          if (!curCall) break;
          const args = curCall[curCall.length - 1];
          const [before, inside, after] = fn(...args);
          before(...args);
          let nextCall = inside(...args);
          callStack.push([[after, args], ...nextCall]);
        }
      };
      return dfs;
    };
    const dfs = helper((u, x, y) => {
      const before = (u, x, y) => {
        st[u] = 1;
        f(y, -1);
        f(x, 1);
      };
      const inside = () => {
        let res = [];
        for (let i = h[u]; i !== -1; i = ne[i]) {
          const v = e[i];
          if (st[v]) continue;
          const [x, y] = w[i];
          res.push([v, x, y]);
        }
        return res;
      };
      const after = (u, x, y) => {
        f(y, 1);
        f(x, -1);
      };
      return [before, inside, after];
    });
    dfs(0, 0, 0);
    let num = 1;
    for (let i = 2; i <= n; i++) {
      if (max[i]) num = mul(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  console.log((ori.reduce((a, b) => a + b, 0) % MOD).toString());
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function power(a, b) {
  let res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  try {
    let t = Number(await read());
    let res = [];
    while (t--) {
      const n = Number(await read());
      const b = [];
      let tmp = n - 1;
      while (tmp--) {
        const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
        b.push([i, j, x, y]);
      }
      res.push(solve(n, b));
    }
  } catch (error) {
    console.log(error);
  }
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  function getPrimes(n) {
    const nums = new Array(n + 1).fill(1);
    nums[0] = nums[1] = 0;
    const primes = [];
    const minp = [];
    for (let i = 2; i <= n; i++) {
      if (nums[i]) {
        primes.push(i);
        minp[i] = i;
      }
      for (let num of primes) {
        const j = num * i;
        if (j > n) break;
        minp[j] = num;
        nums[j] = 0;
        if (i % num === 0) break;
      }
    }
    const res = Array.from({
      length: n + 1
    }, () => new Map());
    for (let i = 1; i <= n; i++) {
      for (let j = i; j > 1; j /= minp[j]) {
        var _res$i$get;
        res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
      }
    }
    return res;
  }
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  const g = Array.from({
    length: n
  }, () => []);
  let idx = 0;
  const add = (i, j, x, y) => {
    g[i].push(j);
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function helper(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      const callStack = [[[u, 0, 0]]];
      while (callStack.length) {
        let curCall = callStack[callStack.length - 1];
        while (((_curCall = curCall) === null || _curCall === void 0 ? void 0 : _curCall.length) === 0) {
          var _curCall;
          callStack.pop();
          curCall = callStack[callStack.length - 1];
          if (!curCall) continue;
          const [v, x, y] = curCall.pop();
          helper(y, 1);
          helper(x, -1);
        }
        if (!curCall) break;
        const [u, x, y] = curCall[curCall.length - 1];
        helper(y, -1);
        helper(x, 1);
        st[u] = 1;
        let nextCall = [];
        for (let i = h[u]; i !== -1; i = ne[i]) {
          const v = e[i];
          if (st[v]) continue;
          const [x, y] = w[i];
          nextCall.push([v, x, y]);
        }
        callStack.push(nextCall);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 2; i <= n; i++) {
      if (max[i]) num = mul(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  console.log((ori.reduce((a, b) => a + b, 0) % MOD).toString());
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function power(a, b) {
  let res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  try {
    let t = Number(await read());
    let res = [];
    while (t--) {
      const n = Number(await read());
      const b = [];
      let tmp = n - 1;
      while (tmp--) {
        const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
        b.push([i, j, x, y]);
      }
      res.push(solve(n, b));
    }
  } catch (error) {
    console.log(error);
  }
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  function getPrimes(n) {
    const nums = new Array(n + 1).fill(1);
    nums[0] = nums[1] = 0;
    const primes = [];
    const minp = [];
    for (let i = 2; i <= n; i++) {
      if (nums[i]) {
        primes.push(i);
        minp[i] = i;
      }
      for (let num of primes) {
        const j = num * i;
        if (j > n) break;
        minp[j] = num;
        nums[j] = 0;
        if (i % num === 0) break;
      }
    }
    const res = Array.from({
      length: n + 1
    }, () => new Map());
    for (let i = 1; i <= n; i++) {
      for (let j = i; j > 1; j /= minp[j]) {
        var _res$i$get;
        res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
      }
    }
    return res;
  }
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  const g = Array.from({
    length: n
  }, () => []);
  let idx = 0;
  const add = (i, j, x, y) => {
    g[i].push(j);
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function helper(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        helper(y, -1);
        helper(x, 1);
        dfs(v);
        helper(y, 1);
        helper(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 2; i <= n; i++) {
      if (max[i]) num = mul(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  console.log((ori.reduce((a, b) => a + b, 0) % MOD).toString());
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function power(a, b) {
  let res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  try {
    let t = Number(await read());
    let res = [];
    while (t--) {
      const n = Number(await read());
      const b = [];
      let tmp = n - 1;
      while (tmp--) {
        const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
        b.push([i, j, x, y]);
      }
      res.push(solve(n, b));
    }
  } catch (error) {
    console.log(error);
  }
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  function getPrimes(n) {
    const nums = new Array(n + 1).fill(1);
    nums[0] = nums[1] = 0;
    const primes = [];
    const minp = [];
    for (let i = 2; i <= n; i++) {
      if (nums[i]) {
        primes.push(i);
        minp[i] = i;
      }
      for (let num of primes) {
        const j = num * i;
        if (j > n) break;
        minp[j] = num;
        nums[j] = 0;
        if (i % num === 0) break;
      }
    }
    const res = Array.from({
      length: n + 1
    }, () => new Map());
    for (let i = 1; i <= n; i++) {
      for (let j = i; j > 1; j /= minp[j]) {
        var _res$i$get;
        res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
      }
    }
    return res;
  }
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  let xs = new Set();
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
    xs.add(x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function helper(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        helper(y, -1);
        helper(x, 1);
        dfs(v);
        helper(y, 1);
        helper(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 2; i <= n; i++) {
      if (max[i]) num = mul(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  console.log((ori.reduce((a, b) => a + b, 0) % MOD).toString());
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function power(a, b) {
  let res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    try {
      res.push(solve(n, b));
    } catch (error) {
      console.log(error);
    }
  }
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  function getPrimes(n) {
    const nums = new Array(n + 1).fill(1);
    nums[0] = nums[1] = 0;
    const primes = [];
    const minp = [];
    for (let i = 2; i <= n; i++) {
      if (nums[i]) {
        primes.push(i);
        minp[i] = i;
      }
      for (let num of primes) {
        const j = num * i;
        if (j > n) break;
        minp[j] = num;
        nums[j] = 0;
        if (i % num === 0) break;
      }
    }
    const res = Array.from({
      length: n + 1
    }, () => new Map());
    for (let i = 1; i <= n; i++) {
      for (let j = i; j > 1; j /= minp[j]) {
        var _res$i$get;
        res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
      }
    }
    return res;
  }
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  let xs = new Set();
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
    xs.add(x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function helper(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        helper(y, -1);
        helper(x, 1);
        dfs(v);
        helper(y, 1);
        helper(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 2; i <= n; i++) {
      if (max[i]) num = mul(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  console.log((ori.reduce((a, b) => a + b, 0) % MOD).toString());
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function power(a, b) {
  let res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    res.push(solve(n, b));
  }
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function getPrimes(n) {
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  const minp = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) {
      primes.push(i);
      minp[i] = i;
    }
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      minp[j] = num;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => new Map());
  for (let i = 1; i <= n; i++) {
    for (let j = i; j > 1; j /= minp[j]) {
      var _res$i$get;
      res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
    }
  }
  return res;
}
function solve(n, a, max) {
  new Date().valueOf();
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  let xs = new Set();
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
    xs.add(x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function power(a, b) {
  let res = 1;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function getPrimes(n) {
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  const minp = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) {
      primes.push(i);
      minp[i] = i;
    }
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      minp[j] = num;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => new Map());
  for (let i = 1; i <= n; i++) {
    for (let j = i; j > 1; j /= minp[j]) {
      var _res$i$get;
      res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
    }
  }
  return res;
}
function solve(n, a, max) {
  new Date().valueOf();
  const primes = getPrimes(n);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  let xs = new Set();
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
    xs.add(x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = new Map();
function power(a, b) {
  var _cache$get;
  let res = (_cache$get = cache.get(a)) === null || _cache$get === void 0 ? void 0 : _cache$get.get(b);
  if (res) return res;
  res = 1;
  let a1 = a,
      b1 = b;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  if (cache.has(a1)) {
    cache.get(a1).set(b1, res);
  } else {
    cache.set(a1, new Map([[b1, res]]));
  }
  return res;
}
function mul(a, b) {
  const N = 16;
  return ((a >> N) * b % MOD * (1 << N) + (a & (1 << N) - 1) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  const minp = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) {
      primes.push(i);
      minp[i] = i;
    }
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      minp[j] = num;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => new Map());
  for (let i = 1; i <= n; i++) {
    for (let j = i; j > 1; j /= minp[j]) {
      var _res$i$get;
      res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
    }
  }
  p = res;
  return res;
}
function solve(n, a, max) {
  new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  let xs = new Set();
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
    xs.add(x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, power(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, power(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = new Map();
function power(a, b) {
  var _cache$get;
  let res = (_cache$get = cache.get(a)) === null || _cache$get === void 0 ? void 0 : _cache$get.get(b);
  if (res) return res;
  res = 1;
  let a1 = a,
      b1 = b;
  while (b) {
    if (b & 1) res = mul(res, a);
    a = mul(a, a);
    b = b >> 1;
  }
  if (cache.has(a1)) {
    cache.get(a1).set(b1, res);
  } else {
    cache.set(a1, new Map([[b1, res]]));
  }
  return res;
}
function mul(a, b) {
  return ((a >> 16) * b % MOD * 65536 + (a & 65535) * b) % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    max = Math.max(max, n);
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  const minp = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) {
      primes.push(i);
      minp[i] = i;
    }
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      minp[j] = num;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => new Map());
  for (let i = 1; i <= n; i++) {
    for (let j = i; j > 1; j /= minp[j]) {
      var _res$i$get;
      res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
    }
  }
  p = res;
  return res;
}
let flag = false;
function solve(n, a, max) {
  if (n === 200000 && a[0][0] === 51097) flag = true;
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  if (n === 200000 && a[0][0] === 51097) {
    console.log('debug1', new Date().valueOf() - time);
    time = new Date().valueOf();
  }
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let res = 0;
    let st = [];
    const dfs = u => {
      res = (res + st[u]) % MOD;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        if (n === 200000 && a[0][0] === 51097) {
          st[v] = mod(st[u], y);
        } else st[v] = mod(st[u], y, quickMi(x, MOD - 2));
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    st[0] = 1;
    dfs(0);
    if (n === 200000 && a[0][0] === 51097) {
      console.log('debug2', new Date().valueOf() - time);
      time = new Date().valueOf();
    }
    for (let i = 1; i <= n; i++) {
      if (max[i]) res = mod(res, quickMi(i, max[i]));
    }
    if (n === 200000 && a[0][0] === 51097) {
      console.log('debug3', new Date().valueOf() - time);
    }
    return res;
  }
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = new Map();
function quickMi(a, b) {
  const state = `${a},${b}`;
  if (cache.has(state)) return cache.get(state);
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  cache.set(state, res);
  return res;
}
const MAXN = 9 * 10 ** 15;
function mul(a, b) {
  if (flag) return a * b % MOD;
  let num = a * b;
  if (num > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return num >= MOD ? num % MOD : num;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    max = Math.max(max, n);
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
    if (n === 200000 && b[0][0] === 51097) {
      res.push(solve(n, b, n));
    }
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  const minp = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) {
      primes.push(i);
      minp[i] = i;
    }
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      minp[j] = num;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => new Map());
  for (let i = 1; i <= n; i++) {
    for (let j = i; j > 1; j /= minp[j]) {
      var _res$i$get;
      res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
    }
  }
  p = res;
  return res;
}
let flag = false;
function solve(n, a, max) {
  if (n === 200000 && a[0][0] === 51097) flag = true;
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  if (n === 200000 && a[0][0] === 51097) {
    console.log('debug1', new Date().valueOf() - time);
    time = new Date().valueOf();
  }
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let res = 0;
    let st = [];
    const dfs = u => {
      res = (res + st[u]) % MOD;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        if (n === 200000 && a[0][0] === 51097) ; else st[v] = mod(st[u], y, quickMi(x, MOD - 2));
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    st[0] = 1;
    dfs(0);
    if (n === 200000 && a[0][0] === 51097) {
      console.log('debug2', new Date().valueOf() - time);
      time = new Date().valueOf();
    }
    for (let i = 1; i <= n; i++) {
      if (max[i]) res = mod(res, quickMi(i, max[i]));
    }
    if (n === 200000 && a[0][0] === 51097) {
      console.log('debug3', new Date().valueOf() - time);
    }
    return res;
  }
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = new Map();
function quickMi(a, b) {
  const state = `${a},${b}`;
  if (cache.has(state)) return cache.get(state);
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  cache.set(state, res);
  return res;
}
const MAXN = 9 * 10 ** 15;
function mul(a, b) {
  if (flag) return a * b % MOD;
  let num = a * b;
  if (num > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return num >= MOD ? num % MOD : num;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    max = Math.max(max, n);
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
    if (n === 200000 && b[0][0] === 51097) {
      res.push(solve(n, b, n));
    }
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  const minp = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) {
      primes.push(i);
      minp[i] = i;
    }
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      minp[j] = num;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => new Map());
  for (let i = 1; i <= n; i++) {
    for (let j = i; j > 1; j /= minp[j]) {
      var _res$i$get;
      res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
    }
  }
  p = res;
  return res;
}
let flag = false;
function solve(n, a, max) {
  if (n === 200000 && a[0][0] === 51097) flag = true;
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  if (n === 200000 && a[0][0] === 51097) {
    console.log('debug1', new Date().valueOf() - time);
    time = new Date().valueOf();
  }
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let res = 0;
    let st = [];
    const dfs = u => {
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        st[v] = mod(st[u], y);
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    st[0] = 1;
    dfs(0);
    if (n === 200000 && a[0][0] === 51097) {
      console.log('debug2', new Date().valueOf() - time);
      time = new Date().valueOf();
    }
    for (let i = 1; i <= n; i++) {
      if (max[i]) res = mod(res, quickMi(i, max[i]));
    }
    if (n === 200000 && a[0][0] === 51097) {
      console.log('debug3', new Date().valueOf() - time);
    }
    return res;
  }
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = new Map();
function quickMi(a, b) {
  const state = `${a},${b}`;
  if (cache.has(state)) return cache.get(state);
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  cache.set(state, res);
  return res;
}
const MAXN = 9 * 10 ** 15;
function mul(a, b) {
  if (flag) return a * b % MOD;
  let num = a * b;
  if (num > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return num >= MOD ? num % MOD : num;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    max = Math.max(max, n);
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
    if (n === 200000 && b[0][0] === 51097) {
      res.push(solve(n, b, n));
    }
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  const minp = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) {
      primes.push(i);
      minp[i] = i;
    }
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      minp[j] = num;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => new Map());
  for (let i = 1; i <= n; i++) {
    for (let j = i; j > 1; j /= minp[j]) {
      var _res$i$get;
      res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
    }
  }
  p = res;
  return res;
}
function solve(n, a, max) {
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  if (n === 200000 && a[0][0] === 51097) {
    console.log('debug1', new Date().valueOf() - time);
    time = new Date().valueOf();
  }
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let res = 0;
    let st = [];
    const dfs = u => {
      res = (res + st[u]) % MOD;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        st[v] = mod(st[u], y, quickMi(x, MOD - 2));
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    st[0] = 1;
    dfs(0);
    if (n === 200000 && a[0][0] === 51097) {
      console.log('debug2', new Date().valueOf() - time);
      time = new Date().valueOf();
    }
    for (let i = 1; i <= n; i++) {
      if (max[i]) res = mod(res, quickMi(i, max[i]));
    }
    if (n === 200000 && a[0][0] === 51097) {
      console.log('debug3', new Date().valueOf() - time);
    }
    return res;
  }
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res;else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 9 * 10 ** 15;
const cache1 = {};
function mul(a, b) {
  var _cache1$a;
  if ((_cache1$a = cache1[a]) !== null && _cache1$a !== void 0 && _cache1$a[b]) return cache1[a][b];
  let num = a * b,
      res = 0;
  if (num > MAXN) res = Number(BigInt(a) * BigInt(b) % BigInt(MOD));else res = num > MOD ? num % MOD : num;
  if (cache1[a]) {
    cache1[a][b] = res;
  } else {
    cache[a] = {
      [b]: res
    };
  }
  return res;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    max = Math.max(max, n);
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
    if (n === 200000 && b[0][0] === 51097) {
      res.push(solve(n, b, n));
    }
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  const minp = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) {
      primes.push(i);
      minp[i] = i;
    }
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      minp[j] = num;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => new Map());
  for (let i = 1; i <= n; i++) {
    for (let j = i; j > 1; j /= minp[j]) {
      var _res$i$get;
      res[i].set(minp[j], ((_res$i$get = res[i].get(minp[j])) !== null && _res$i$get !== void 0 ? _res$i$get : 0) + 1);
    }
  }
  p = res;
  return res;
}
function solve(n, a, max) {
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res;else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  let num = a * b;
  if (num > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return num > MOD ? num % MOD : num;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    max = Math.max(max, n);
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
    if (n === 200000) {
      res.push(solve(n, b, n));
    }
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => []);
  for (let i = 1; i <= n; i++) {
    for (let num of primes) {
      if (i < num) break;
      if (i % num === 0) {
        let t = i;
        let count = 0;
        while (t % num === 0) {
          count++;
          t /= num;
        }
        res[i].push([num, count]);
      }
    }
  }
  p = res;
  return res;
}
function solve(n, a, max) {
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  if (n === 20000) console.log(time);
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res;else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
let time = 0;
function mul(a, b) {
  const t = new Date().valueOf();
  let num = a * b,
      res = 0;
  if (num > MAXN) res = Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  res = num > MOD ? num % MOD : num;
  time += new Date().valueOf() - t;
  return res;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    max = Math.max(max, n);
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy(e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

let times$1 = new Array(4).fill(0);
const MOD = 998244353;
let p = null;
let tt = 0
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => []);

  for (let i = 1; i <= n; i++) {
    for (let num of primes) {
      if (i < num) break;
      if (i % num === 0) {
        let t = i;
        let count = 0;
        while (t % num === 0) {
          count++;
          t /= num;
        }
        res[i].push([num, count]);
      }
    }
  }
  p = res;

  return res;
}
function solve(n, a, max) {
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
    e = [],
    ne = [],
    d = new Array(n).fill(0),
    w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  times$1[0] += new Date().valueOf() - time;
  time = new Date().valueOf();
  const ori = [];

  {
    const counts = new Array(n + 1).fill(0),
      max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }

  times$1[1] += new Date().valueOf() - time;
  time = new Date().valueOf();
  {
    let queue = [0],
      st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  times$1[2] += new Date().valueOf() - time;
  time = new Date().valueOf();
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res; else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  tt = t;
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      max = Math.max(max, x, y);
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
    if (tt === 10) {
      console.log(times$1.join(','));
    }
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy(e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

let times$1 = new Array(4).fill(0);
const MOD = 998244353;
let p = null;
let tt = 0
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => []);

  for (let i = 1; i <= n; i++) {
    for (let num of primes) {
      if (i < num) break;
      if (i % num === 0) {
        let t = i;
        let count = 0;
        while (t % num === 0) {
          count++;
          t /= num;
        }
        res[i].push([num, count]);
      }
    }
  }
  p = res;

  return res;
}
function solve(n, a, max) {
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
    e = [],
    ne = [],
    d = new Array(n).fill(0),
    w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  times$1[0] += new Date().valueOf() - time;
  time = new Date().valueOf();
  const ori = [];

  {
    const counts = new Array(n + 1).fill(0),
      max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  if (tt === 10) {
    console.log(n)
    return res
  }
  times$1[1] += new Date().valueOf() - time;
  time = new Date().valueOf();
  {
    let queue = [0],
      st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  times$1[2] += new Date().valueOf() - time;
  time = new Date().valueOf();
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res; else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  tt = t;
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      max = Math.max(max, x, y);
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
    if (tt === 10) {
      console.log(times.join(','));
    }
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy(e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

let times$1 = new Array(4).fill(0);
const MOD = 998244353;
let p = null;
let tt = 0
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => []);

  for (let i = 1; i <= n; i++) {
    for (let num of primes) {
      if (i < num) break;
      if (i % num === 0) {
        let t = i;
        let count = 0;
        while (t % num === 0) {
          count++;
          t /= num;
        }
        res[i].push([num, count]);
      }
    }
  }
  p = res;

  return res;
}
function solve(n, a, max) {
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
    e = [],
    ne = [],
    d = new Array(n).fill(0),
    w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  times$1[0] += new Date().valueOf() - time;
  time = new Date().valueOf();
  const ori = [];
  if (tt === 10) {
    console.log(n)
    return res
  }
  {
    const counts = new Array(n + 1).fill(0),
      max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  times$1[1] += new Date().valueOf() - time;
  time = new Date().valueOf();
  {
    let queue = [0],
      st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  times$1[2] += new Date().valueOf() - time;
  time = new Date().valueOf();
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res; else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  tt = t;
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      max = Math.max(max, x, y);
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
    if (tt === 10) {
      console.log(times.join(','));
    }
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy(e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

let times$1 = new Array(4).fill(0);
const MOD = 998244353;
let p = null;
let tt = 0
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => []);

  for (let i = 1; i <= n; i++) {
    for (let num of primes) {
      if (i < num) break;
      if (i % num === 0) {
        let t = i;
        let count = 0;
        while (t % num === 0) {
          count++;
          t /= num;
        }
        res[i].push([num, count]);
      }
    }
  }
  p = res;
  if (tt === 10) {
    console.log(n)
    return res
  }
  return res;
}
function solve(n, a, max) {
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
    e = [],
    ne = [],
    d = new Array(n).fill(0),
    w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  times$1[0] += new Date().valueOf() - time;
  time = new Date().valueOf();
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
      max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  times$1[1] += new Date().valueOf() - time;
  time = new Date().valueOf();
  {
    let queue = [0],
      st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  times$1[2] += new Date().valueOf() - time;
  time = new Date().valueOf();
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res; else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  tt = t;
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      max = Math.max(max, x, y);
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
    if (tt === 10) {
      console.log(times.join(','));
    }
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy(e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

let times$1 = new Array(4).fill(0);
const MOD = 998244353;
let p = null;
let tt = 0
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => []);
  if (tt === 10) {
    console.log(n)
    return res
  }
  for (let i = 1; i <= n; i++) {
    for (let num of primes) {
      if (i < num) break;
      if (i % num === 0) {
        let t = i;
        let count = 0;
        while (t % num === 0) {
          count++;
          t /= num;
        }
        res[i].push([num, count]);
      }
    }
  }
  p = res;
  return res;
}
function solve(n, a, max) {
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
    e = [],
    ne = [],
    d = new Array(n).fill(0),
    w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  times$1[0] += new Date().valueOf() - time;
  time = new Date().valueOf();
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
      max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  times$1[1] += new Date().valueOf() - time;
  time = new Date().valueOf();
  {
    let queue = [0],
      st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  times$1[2] += new Date().valueOf() - time;
  time = new Date().valueOf();
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res; else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  tt = t;
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      max = Math.max(max, x, y);
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
    if (tt === 10) {
      console.log(times.join(','));
    }
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy(e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

let times$1 = new Array(4).fill(0);
const MOD = 998244353;
let p = null;
let tt = 0
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => []);
  if (tt === 10) return res
  for (let i = 1; i <= n; i++) {
    for (let num of primes) {
      if (i < num) break;
      if (i % num === 0) {
        let t = i;
        let count = 0;
        while (t % num === 0) {
          count++;
          t /= num;
        }
        res[i].push([num, count]);
      }
    }
  }
  p = res;
  return res;
}
function solve(n, a, max) {
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
    e = [],
    ne = [],
    d = new Array(n).fill(0),
    w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  times$1[0] += new Date().valueOf() - time;
  time = new Date().valueOf();
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
      max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  times$1[1] += new Date().valueOf() - time;
  time = new Date().valueOf();
  {
    let queue = [0],
      st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  times$1[2] += new Date().valueOf() - time;
  time = new Date().valueOf();
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res; else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  tt = t;
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      max = Math.max(max, x, y);
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
    if (tt === 10) {
      console.log(times.join(','));
    }
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy(e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

let times$1 = new Array(4).fill(0);
const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => []);
  if (tt === 10) return res
  for (let i = 1; i <= n; i++) {
    for (let num of primes) {
      if (i < num) break;
      if (i % num === 0) {
        let t = i;
        let count = 0;
        while (t % num === 0) {
          count++;
          t /= num;
        }
        res[i].push([num, count]);
      }
    }
  }
  p = res;
  return res;
}
function solve(n, a, max) {
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
    e = [],
    ne = [],
    d = new Array(n).fill(0),
    w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  times$1[0] += new Date().valueOf() - time;
  time = new Date().valueOf();
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
      max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  times$1[1] += new Date().valueOf() - time;
  time = new Date().valueOf();
  {
    let queue = [0],
      st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  times$1[2] += new Date().valueOf() - time;
  time = new Date().valueOf();
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res; else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  let tt = t;
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      max = Math.max(max, x, y);
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
    if (tt === 10) {
      console.log(times.join(','));
    }
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy(e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

let times$1 = new Array(4).fill(0);
const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => []);
  if(tt=10)return res
  for (let i = 1; i <= n; i++) {
    for (let num of primes) {
      if (i < num) break;
      if (i % num === 0) {
        let t = i;
        let count = 0;
        while (t % num === 0) {
          count++;
          t /= num;
        }
        res[i].push([num, count]);
      }
    }
  }
  p = res;
  return res;
}
function solve(n, a, max) {
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
    e = [],
    ne = [],
    d = new Array(n).fill(0),
    w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  times$1[0] += new Date().valueOf() - time;
  time = new Date().valueOf();
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
      max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  times$1[1] += new Date().valueOf() - time;
  time = new Date().valueOf();
  {
    let queue = [0],
      st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  times$1[2] += new Date().valueOf() - time;
  time = new Date().valueOf();
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res; else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  let tt = t;
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      max = Math.max(max, x, y);
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
    if (tt === 10) {
      console.log(times.join(','));
    }
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

let times$1 = new Array(4).fill(0);
const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  const res = Array.from({
    length: n + 1
  }, () => []);
  for (let i = 1; i <= n; i++) {
    for (let num of primes) {
      if (i < num) break;
      if (i % num === 0) {
        let t = i;
        let count = 0;
        while (t % num === 0) {
          count++;
          t /= num;
        }
        res[i].push([num, count]);
      }
    }
  }
  p = res;
  return res;
}
function solve(n, a, max) {
  let time = new Date().valueOf();
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  times$1[0] += new Date().valueOf() - time;
  time = new Date().valueOf();
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      for (let [i, count] of primes[n]) {
        counts[i] += count * flag;
        max[i] = Math.max(max[i], counts[i]);
      }
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  times$1[1] += new Date().valueOf() - time;
  time = new Date().valueOf();
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  times$1[2] += new Date().valueOf() - time;
  time = new Date().valueOf();
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res;else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  let tt = t;
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      max = Math.max(max, x, y);
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
    if (tt === 10) {
      console.log(times.join(','));
    }
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy(e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);
let times = new Array(3).fill(0)
const MOD = 998244353;
let p = null;
function getPrimes(n) {
  if (p) return p;
  const nums = new Array(n + 1).fill(1);
  nums[0] = nums[1] = 0;
  const primes = [];
  for (let i = 2; i <= n; i++) {
    if (nums[i]) primes.push(i);
    for (let num of primes) {
      const j = num * i;
      if (j > n) break;
      nums[j] = 0;
      if (i % num === 0) break;
    }
  }
  p = primes;
  return primes;
}
function solve(n, a, max) {
  let time = new Date().valueOf()
  const primes = getPrimes(max);
  const h = new Array(n).fill(-1),
    e = [],
    ne = [],
    d = new Array(n).fill(0),
    w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  times[0] += new Date().valueOf() - time
  time = new Date().valueOf()
  const ori = [];
  {
    const counts = new Array(n + 1).fill(0),
      max = new Array(n + 1).fill(0);
    const cache = new Map();
    function divide(n, flag) {
      let tmp = n;
      if (cache.has(n)) {
        for (let [i, count] of cache.get(n)) {
          counts[i] += count * flag;
          max[i] = Math.max(max[i], counts[i]);
        }
        return;
      }
      let res = [];
      for (let i of primes) {
        if (n % i === 0) {
          let count = 0;
          while (n % i === 0) {
            count++;
            n /= i;
          }
          counts[i] += count * flag;
          max[i] = Math.max(max[i], counts[i]);
          res.push([i, count]);
        }
      }
      cache.set(tmp, res);
    }
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  times[1] += new Date().valueOf() - time
  time = new Date().valueOf()
  {
    let queue = [0],
      st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  times[2] += new Date().valueOf() - time
  time = new Date().valueOf()
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
const cache = {};
function quickMi(a, b) {
  var _cache$a;
  if ((_cache$a = cache[a]) !== null && _cache$a !== void 0 && _cache$a[b]) return cache[a][b];
  if (b === 0) return 1;
  let res = 1;
  if (b & 1) {
    res = mul(quickMi(mul(a, a), (b - 1) / 2), a);
  } else {
    res = quickMi(mul(a, a), b / 2);
  }
  if (cache[a]) cache[a][b] = res; else cache[a] = {
    [b]: res
  };
  return res;
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let max = 0;
  let params = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      const [i, j, x, y] = (await read()).split(' ').map(s => Number(s));
      max = Math.max(max, x, y);
      b.push([i, j, x, y]);
    }
    params.push([n, b]);
  }
  for (let [n, b] of params) {
    res.push(solve(n, b, max));
    if (tt === 10) {
      console.log(times.join(','))
    }
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  const cache = new Map();
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
    if (!cache.has(x)) cache.set(x, []);
    if (!cache.has(y)) cache.set(y, []);
  }
  const ori = [];
  {
    const primes = new Array(n + 1).fill(0),
          max = new Array(n + 1).fill(0);
    function divide(n, flag) {
      if (!cache.has(n)) console.log(n, cache.has(n), flag);
      for (let [i, count] of cache.get(n)) {
        primes[i] += count * flag;
        max[i] = Math.max(max[i], primes[i]);
      }
    }
    function getPrimes(n) {
      const nums = new Array(n + 1).fill(1),
            primes = [];
      nums[0] = nums[1] = 0;
      for (let i = 2; i <= n / i; i++) {
        for (let j = i + i; j <= n; j += i) {
          nums[j] = 0;
          if (cache.has(j)) {
            let count = 0;
            let t = j;
            while (t % i === 0) {
              count++;
              t /= i;
            }
            cache.get(j).push([i, count]);
          }
        }
      }
      for (let i = 0; i <= n; i++) if (nums[i]) {
        if (cache.has(i)) {
          cache.get(i).push([i, 1]);
        }
        primes.push(i);
      }
      return primes;
    }
    getPrimes(n);
    let st = [];
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i <= n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  {
    let queue = [0],
        st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [0],
      st = [];
      Array.from({
    length: n
  }, () => [1, 1]);
  const ori = [];
  const primes = new Array(n).fill(0),
        max = new Array(n).fill(0);
  {
    function divide(n, flag) {
      for (let i = 2; i <= n / i; i++) {
        if (n % i === 0) {
          let count = 0;
          while (n % i === 0) {
            count++;
            n /= i;
          }
          primes[i] += count * flag;
          max[i] = Math.max(max[i], primes[i]);
        }
      }
      if (n !== 1) {
        primes[n] += flag;
        max[n] = Math.max(max[n], primes[n]);
      }
    }
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i < n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  {
    st = [];
    queue = [0];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let t1=t
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    if(t1===10000&&n===17)console.log(b.join('|'))
    res.push(solve(n, b));
  }
  if(t1!==10000) console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [0],
      st = [];
      Array.from({
    length: n
  }, () => [1, 1]);
  const ori = [];
  const primes = new Array(n).fill(0),
        max = new Array(n).fill(0);
  {
    function divide(n, flag) {
      for (let i = 2; i <= n / i; i++) {
        if (n % i === 0) {
          let count = 0;
          while (n % i === 0) {
            count++;
            n /= i;
          }
          primes[i] += count * flag;
          max[i] = Math.max(max[i], primes[i]);
        }
      }
      if (n !== 1) {
        primes[n] += flag;
        max[n] = Math.max(max[n], primes[n]);
      }
    }
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i < n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  {
    st = [];
    queue = [0];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let t1=t
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    if(t1===10000&&n===17)console.log(b.join(','))
    res.push(solve(n, b));
  }
  if(t1!==10000) console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [0],
      st = [];
      Array.from({
    length: n
  }, () => [1, 1]);
  const ori = [];
  const primes = new Array(n).fill(0),
        max = new Array(n).fill(0);
  {
    function divide(n, flag) {
      for (let i = 2; i <= n / i; i++) {
        if (n % i === 0) {
          let count = 0;
          while (n % i === 0) {
            count++;
            n /= i;
          }
          primes[i] += count * flag;
          max[i] = Math.max(max[i], primes[i]);
        }
      }
      if (n !== 1) {
        primes[n] += flag;
        max[n] = Math.max(max[n], primes[n]);
      }
    }
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i < n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  {
    st = [];
    queue = [0];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  let tmp=t
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    if(tmp===10000&&n===17)console.log(b.join(','))
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [0],
      st = [];
      Array.from({
    length: n
  }, () => [1, 1]);
  const ori = [];
  const primes = new Array(n).fill(0),
        max = new Array(n).fill(0);
  {
    function divide(n, flag) {
      for (let i = 2; i <= n / i; i++) {
        if (n % i === 0) {
          let count = 0;
          while (n % i === 0) {
            count++;
            n /= i;
          }
          primes[i] += count * flag;
          max[i] = Math.max(max[i], primes[i]);
        }
      }
      if (n !== 1) {
        primes[n] += flag;
        max[n] = Math.max(max[n], primes[n]);
      }
    }
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i < n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  {
    st = [];
    queue = [0];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    if(t===10000&&n===17)console.log(b.join(','))
    res.push(solve(n, b));
  }
  if(t!==10000) console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [0],
      st = [];
      Array.from({
    length: n
  }, () => [1, 1]);
  const ori = [];
  const primes = new Array(n).fill(0),
        max = new Array(n).fill(0);
  {
    function divide(n, flag) {
      for (let i = 2; i <= n / i; i++) {
        if (n % i === 0) {
          let count = 0;
          while (n % i === 0) {
            count++;
            n /= i;
          }
          primes[i] += count * flag;
          max[i] = Math.max(max[i], primes[i]);
        }
      }
      if (n !== 1) {
        primes[n] += flag;
        max[n] = Math.max(max[n], primes[n]);
      }
    }
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i < n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  {
    st = [];
    queue = [0];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    if(t===10000&&n===17)console.log(b.join(','))
    res.push(solve(n, b));
  }
//   console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [0],
      st = [];
      Array.from({
    length: n
  }, () => [1, 1]);
  const ori = [];
  const primes = new Array(n).fill(0),
        max = new Array(n).fill(0);
  {
    function divide(n, flag) {
      for (let i = 2; i <= n / i; i++) {
        if (n % i === 0) {
          let count = 0;
          while (n % i === 0) {
            count++;
            n /= i;
          }
          primes[i] += count * flag;
          max[i] = Math.max(max[i], primes[i]);
        }
      }
      if (n !== 1) {
        primes[n] += flag;
        max[n] = Math.max(max[n], primes[n]);
      }
    }
    const dfs = u => {
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        const [x, y] = w[i];
        divide(y, -1);
        divide(x, 1);
        dfs(v);
        divide(y, 1);
        divide(x, -1);
      }
    };
    dfs(0);
    let num = 1;
    for (let i = 1; i < n; i++) {
      if (max[i]) num = mod(num, quickMi(i, max[i]));
    }
    ori[0] = num;
  }
  {
    st = [];
    queue = [0];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = new Array(n).fill(1);
  const ori = [];
  {
    for (let [i, v] of d.entries()) if (v === 1) {
      queue.push(i);
      dist[i] = 1;
    }
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        const [x, y] = w[i];
        if (dist[u] % x !== 0) {
          dist[u] = mod(dist[u], x, quickMi(gcd(dist[u], x), MOD - 2));
        }
        const num = dist[u] * y / x;
        dist[v] = mod(dist[v], num, quickMi(gcd(dist[v], num), MOD - 2));
        d[v]--;
        if (d[v] === 1) queue.push(v);
      }
    }
  }
  {
    st = [];
    let last = queue[queue.length - 1];
    queue = [last];
    st[queue[0]] = 1;
    ori[last] = dist[last];
    for (let u of queue) {
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        st[v] = 1;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = new Array(n).fill(1);
  const ori = [];
  {
    for (let [i, v] of d.entries()) if (v === 1) {
      queue.push(i);
      dist[i] = 1;
    }
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        const [x, y] = w[i];
        if (dist[u] === Infinity) console.log('11111');
        if (dist[u] % x !== 0) {
          dist[u] = dist[u] * x / gcd(dist[u], x);
        }
        if (dist[v] === Infinity) console.log('22222');
        const num = dist[u] * y / x;
        dist[v] = dist[v] * num / gcd(dist[v], num);
        d[v]--;
        if (d[v] === 1) queue.push(v);
      }
    }
  }
  if (n === 20000) console.log('11111');
  {
    st = [];
    let last = queue[queue.length - 1];
    queue = [last];
    st[queue[0]] = 1;
    ori[last] = dist[last];
    for (let u of queue) {
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        st[v] = 1;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = new Array(n).fill(1);
  const ori = [];
  {
    for (let [i, v] of d.entries()) if (v === 1) {
      queue.push(i);
      dist[i] = 1;
    }
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        const [x, y] = w[i];
        if (dist[u] % x !== 0) {
          dist[u] = dist[u] * x / gcd(dist[u], x);
        }
        const num = dist[u] * y / x;
        dist[v] = dist[v] * num / gcd(dist[v], num);
        d[v]--;
        if (d[v] === 1) queue.push(v);
      }
    }
  }
  if (n === 20000) console.log('11111');
  {
    st = [];
    let last = queue[queue.length - 1];
    queue = [last];
    st[queue[0]] = 1;
    ori[last] = dist[last];
    for (let u of queue) {
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        st[v] = 1;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = new Array(n).fill(1);
  const ori = [];
  if (n === 20000) console.log('11111');
  {
    for (let [i, v] of d.entries()) if (v === 1) {
      queue.push(i);
      dist[i] = 1;
    }
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        const [x, y] = w[i];
        if (dist[u] % x !== 0) {
          dist[u] = dist[u] * x / gcd(dist[u], x);
        }
        const num = dist[u] * y / x;
        dist[v] = dist[v] * num / gcd(dist[v], num);
        d[v]--;
        if (d[v] === 1) queue.push(v);
      }
    }
  }
  {
    st = [];
    let last = queue[queue.length - 1];
    queue = [last];
    st[queue[0]] = 1;
    ori[last] = dist[last];
    for (let u of queue) {
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        st[v] = 1;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  if (n === 20000) console.log('11111');
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = new Array(n).fill(1);
  const ori = [];
  {
    for (let [i, v] of d.entries()) if (v === 1) {
      queue.push(i);
      dist[i] = 1;
    }
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        const [x, y] = w[i];
        if (dist[u] % x !== 0) {
          dist[u] = dist[u] * x / gcd(dist[u], x);
        }
        const num = dist[u] * y / x;
        dist[v] = dist[v] * num / gcd(dist[v], num);
        d[v]--;
        if (d[v] === 1) queue.push(v);
      }
    }
  }
  {
    st = [];
    let last = queue[queue.length - 1];
    queue = [last];
    st[queue[0]] = 1;
    ori[last] = dist[last];
    for (let u of queue) {
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        st[v] = 1;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  console.log('11111');
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = new Array(n).fill(1);
  const ori = [];
  {
    for (let [i, v] of d.entries()) if (v === 1) {
      queue.push(i);
      dist[i] = 1;
    }
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        const [x, y] = w[i];
        if (dist[u] % x !== 0) {
          dist[u] = dist[u] * x / gcd(dist[u], x);
        }
        const num = dist[u] * y / x;
        dist[v] = dist[v] * num / gcd(dist[v], num);
        d[v]--;
        if (d[v] === 1) queue.push(v);
      }
    }
  }
  {
    st = [];
    let last = queue[queue.length - 1];
    queue = [last];
    st[queue[0]] = 1;
    ori[last] = dist[last];
    for (let u of queue) {
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        st[v] = 1;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = new Array(n).fill(1);
  const ori = [];
  {
    for (let [i, v] of d.entries()) if (v === 1) {
      queue.push(i);
      dist[i] = 1;
    }
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        const [x, y] = w[i];
        if (dist[u] % x !== 0) {
          dist[u] = dist[u] * x / gcd(dist[u], x);
        }
        const num = dist[u] * y / x;
        dist[v] = dist[v] * num / gcd(dist[v], num);
        d[v]--;
        if (d[v] === 1) queue.push(v);
      }
    }
  }
  if (n === 20000) console.log(dist.join(','));
  {
    st = [];
    let last = queue[queue.length - 1];
    queue = [last];
    st[queue[0]] = 1;
    ori[last] = dist[last];
    for (let u of queue) {
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        st[v] = 1;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

const MOD = 998244353;
function solve(n, a) {
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = new Array(n).fill(1);
  const ori = [];
  {
    for (let [i, v] of d.entries()) if (v === 1) {
      queue.push(i);
      dist[i] = 1;
    }
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        const [x, y] = w[i];
        if (dist[u] % x !== 0) {
          dist[u] = dist[u] * x / gcd(dist[u], x);
        }
        const num = dist[u] * y / x;
        dist[v] = dist[v] * num / gcd(dist[v], num);
        d[v]--;
        if (d[v] === 1) queue.push(v);
      }
    }
  }
  {
    st = [];
    let last = queue[queue.length - 1];
    queue = [last];
    st[queue[0]] = 1;
    ori[last] = dist[last];
    for (let u of queue) {
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        st[v] = 1;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = mod(ori[u], y, quickMi(x, MOD - 2));
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}
function quickMi(a, b) {
  if (b === 0) return 1;
  if (b & 1) {
    return mul(quickMi(mul(a, a), (b - 1) / 2), a);
  }
  return quickMi(mul(a, a), b / 2);
}
const MAXN = 10 ** 15;
function mul(a, b) {
  if (a * b > MAXN) return Number(BigInt(a) * BigInt(b) % BigInt(MOD));
  return a * b % MOD;
}
function mod(...args) {
  let res = 1;
  for (let i = 0; i < args.length; i++) {
    res = mul(res, args[i]);
  }
  return res;
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

function solve(n, a) {
  const MOD = 998244353;
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = gcd(x, y);
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = new Array(n).fill(1);
  const ori = [];
  {
    for (let [i, v] of d.entries()) if (v === 1) {
      queue.push(i);
      dist[i] = 1;
    }
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        const [x, y] = w[i];
        if (dist[u] % x !== 0) {
          dist[u] = dist[u] * x / gcd(dist[u], x);
        }
        const num = dist[u] * y / x;
        dist[v] = dist[v] * num / gcd(dist[v], num);
        d[v]--;
        if (d[v] === 1) queue.push(v);
      }
    }
  }
  {
    st = [];
    let last = queue[queue.length - 1];
    queue = [last];
    st[queue[0]] = 1;
    ori[last] = dist[last];
    for (let u of queue) {
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        st[v] = 1;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = ori[u] * y / x;
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0) % MOD).toString();
}
function gcd(a, b) {
  return a % b === 0 ? b : gcd(b, a % b);
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

function solve(n, a) {
  const MOD = 998244353;
  const h = new Array(n).fill(-1),
        e = [],
        ne = [];
        new Array(n).fill(0);
        const w = [];
  let idx = 0;
  const p = [...new Array(n).keys()];
  function find(i) {
    while (i !== p[i]) {
      p[i] = p[p[i]];
      i = p[p[i]];
    }
    return i;
  }
  function union(i, j) {
    const [rooti, rootj] = [find(i), find(j)];
    if (rooti === rootj) return;
    p[rootj] = rooti;
  }
  const add = (i, j, x, y) => {
    union(i, j);
    e[idx] = j, ne[idx] = h[i], w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = Number(gcd(BigInt(x), BigInt(y)));
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = [];
  const ori = [];
  let roots = new Set();
  {
    for (let i = 0; i < n; i++) roots.add(find(i));
    for (let root of roots) {
      dist[root] = 1n;
      queue.push(root);
      let num = 1n;
      for (let u of queue) {
        if (st[u]) continue;
        st[u] = 1;
        for (let i = h[u]; i !== -1; i = ne[i]) {
          const v = e[i];
          if (st[v]) continue;
          queue.push(v);
          const [x, y] = w[i].map(BigInt);
          let tmp = dist[u];
          if (tmp % x !== 0n) {
            tmp = tmp * x / gcd(tmp, x);
            num *= tmp / dist[u];
            dist[u] = tmp;
          }
          dist[v] = tmp * y / x;
        }
      }
      ori[root] = num;
    }
  }
  {
    st = [];
    for (let root of roots) {
      if (st[root]) continue;
      queue = [root];
      for (let u of queue) {
        st[u] = 1;
        for (let i = h[u]; i !== -1; i = ne[i]) {
          const v = e[i];
          if (st[v]) continue;
          st[v] = 1;
          queue.push(v);
          const [x, y] = w[i];
          ori[v] = ori[u] * BigInt(y) / BigInt(x);
        }
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0n) % BigInt(MOD)).toString();
}
function gcd(a, b) {
  return a % b === 0n ? b : gcd(b, a % b);
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

function solve(n, a) {
  const MOD = 998244353;
  const h = new Array(n).fill(-1),
        e = [],
        ne = [];
        new Array(n).fill(0);
        const w = [];
  let idx = 0;
  const p = [...new Array(n).keys()];
  function find(i) {
    while (i !== p[i]) {
      p[i] = p[p[i]];
      i = p[p[i]];
    }
    return i;
  }
  function union(i, j) {
    const [rooti, rootj] = [find(i), find(j)];
    if (rooti === rootj) return;
    p[rootj] = rooti;
  }
  const add = (i, j, x, y) => {
    union(i, j);
    e[idx] = j, ne[idx] = h[i], w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = Number(gcd(BigInt(x), BigInt(y)));
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      dist = [];
  const ori = [];
  let roots = new Set();
  {
    for (let i = 0; i < n; i++) roots.add(find(i));
    for (let root of roots) {
      dist[root] = 1n;
      queue.push(root);
      let num = 1n;
      for (let u of queue) {
        if (st[u]) continue;
        st[u] = 1;
        for (let i = h[u]; i !== -1; i = ne[i]) {
          const v = e[i];
          if (st[v]) continue;
          queue.push(v);
          const [x, y] = w[i].map(BigInt);
          let tmp = dist[u];
          if (tmp % x !== 0n) {
            tmp = tmp * x / gcd(tmp, x);
            num *= tmp / dist[u];
            dist[u] = tmp;
          }
          dist[v] = tmp * y / x;
        }
      }
      ori[root] = num;
    }
  }
  {
    st = [];
    for (let root of roots) {
      if (st[root]) continue;
      queue = [root];
      for (let u of queue) {
        if (st[u]) continue;
        st[u] = 1;
        for (let i = h[u]; i !== -1; i = ne[i]) {
          const v = e[i];
          if (st[v]) continue;
          st[v] = 1;
          queue.push(v);
          const [x, y] = w[i];
          ori[v] = ori[u] * BigInt(y) / BigInt(x);
        }
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0n) % BigInt(MOD)).toString();
}
function gcd(a, b) {
  return a % b === 0n ? b : gcd(b, a % b);
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();

'use strict';

var readline = require('readline');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);

function solve(n, a) {
  const MOD = 998244353;
  const h = new Array(n).fill(-1),
        e = [],
        ne = [],
        d = new Array(n).fill(0),
        w = [];
  let idx = 0;
  const add = (i, j, x, y) => {
    e[idx] = j, ne[idx] = h[i], d[j]++, w[idx] = [x, y], h[i] = idx++;
  };
  for (let [i, j, x, y] of a) {
    i--;
    j--;
    const num = Number(gcd(BigInt(x), BigInt(y)));
    x /= num;
    y /= num;
    add(i, j, x, y);
    add(j, i, y, x);
  }
  let queue = [],
      st = [],
      root = -1,
      num = 1n,
      dist = [];
  {
    for (let [k, v] of d.entries()) if (v === 1) {
      queue.push(k);
      root = k;
      break;
    }
    dist[root] = 1n;
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i].map(BigInt);
        let tmp = dist[u];
        if (tmp % x !== 0n) {
          tmp = tmp * x / gcd(tmp, x);
          num *= tmp / dist[u];
          dist[u] = tmp;
        }
        dist[v] = tmp * y / x;
      }
    }
  }
  const ori = [];
  ori[root] = num;
  {
    queue = [root];
    st = [];
    for (let u of queue) {
      if (st[u]) continue;
      st[u] = 1;
      for (let i = h[u]; i !== -1; i = ne[i]) {
        const v = e[i];
        if (st[v]) continue;
        queue.push(v);
        const [x, y] = w[i];
        ori[v] = ori[u] * BigInt(y) / BigInt(x);
      }
    }
  }
  return (ori.reduce((a, b) => a + b, 0n) % BigInt(MOD)).toString();
}
function gcd(a, b) {
  return a % b === 0n ? b : gcd(b, a % b);
}

async function main(read) {
  let t = Number(await read());
  let res = [];
  while (t--) {
    const n = Number(await read());
    const b = [];
    let tmp = n - 1;
    while (tmp--) {
      b.push((await read()).split(' ').map(s => Number(s)));
    }
    res.push(solve(n, b));
  }
  console.log(res.join('\n'));
}

const rl = readline__default["default"].createInterface({
  input: process.stdin,
  output: process.stdout
});
void async function () {
  const inputs = [];
  let i = 0;
  for await (const line of rl) {
    inputs.push(line.trim());
  }
  function read() {
    return inputs[i++];
  }
  await main(read);
}();