rt
#include<atcoder/math>
#define ll long long
#define lll __int128_t
#define ull unsigned long long
#define ld long double
#define rep(i,l,r) for(register ll i=(l);i<=(r);++i)
#define Rep(i,l,r) for(register ll i=(r);i>=(l);--i)
#define all(x) x.begin(),x.end()
#define Set(x,y) memset(x,y,sizeof(x))
#define Cpy(x,y) memcpy(x,y,sizeof(x))
#define cll const long long
using namespace std;
template<class T>
void death(T s){cout<<s<<endl;exit(0);}
cll N=200009;
struct frac{
lll u,d;
frac(lll _u=0,lll _d=1){u=_u/__gcd(_u,_d),d=_d/__gcd(_u,_d); if(d<0)d=-d,u=-u; assert(d!=0); }
bool operator<(const frac&x)const{return u*x.d<x.u*d;}
bool operator>(const frac&x)const{return u*x.d>x.u*d;}
bool operator==(const frac&x)const{return u==x.u&&d==x.d;}
bool operator!=(const frac&x)const{return u!=x.u||d!=x.d;}
frac operator+(const frac&x)const{return frac(u*x.d+d*x.u,d*x.d);}
frac operator-(const frac&x)const{return frac(u*x.d-d*x.u,d*x.d);}
frac operator/(const frac&x)const{assert(x.u!=0); return frac(u*x.d,d*x.u);}
};
lll flor(frac x){return x.u/x.d;}
lll cei(frac x){return (x.u-1)/x.d+1;}
bool integ(frac x){return x.d==1;}
struct Line{
frac b,k; ll id;
bool operator<(const Line&x)const{return k>x.k || k==x.k&&b>x.b;}
#define b(u) lines[u].b
#define k(u) lines[u].k
}lines[N];
struct HalfPlane{ll a,b,c;} p[N];//ax+by<=c
frac X(ll u,ll v){
return (b(v)-b(u))/(k(u)-k(v));
}
ll n,q[N],tno;
const ll MOD=998244353;
void clr(){
rep(i,0,tno){
lines[i]=(Line){frac(),frac(),0};
p[i]=(HalfPlane){0,0,0};
q[i]=0;
}
n=tno=0;
}
void solve(){
cin>>n; tno=n;
rep(i,1,n){
ll a,b,c;
cin>>a>>b>>c;
c--;
lines[i]=(Line){frac(c,b),frac(-a,b),i};
p[i]=(HalfPlane){a,b,c};
}
sort(lines+1,lines+1+n);
ll l=1,r=1;
rep(i,1,n-1)if(k(i)==k(i+1))i--,n--;
rep(i,1,n){
while(r-l>=2&&X(i,q[r-1])<X(q[r-1],q[r-2])) r--;
q[r++]=i;
}
rep(i,1,r-1)lines[i]=lines[q[i]];
n=r-1;
ll ans=0;
rep(l,1,n){
ll id=lines[l].id;
lll x0=1,x1=flor(X(l,0));
if(l!=1){
frac a=X(l,l-1);
x0=cei(a)+integ(a);
}
if(l!=n){
frac a=X(l,l+1);
x1=flor(a);
}
if(x0<1)x0=1;
x1=min(x1,flor(X(l,0)));
if(x1<x0)continue;
/*
对于直线y=kx+b x in [l,r]
ax+by<=c
即求 by<=c-ax的和
求sigma[l...r] floor((-ax+c)/b)
-> sigma[0...r-l] floor((-a(x+l)+c)/b)
-> sigma[0...r-l] floor(( (-a)x+(c-a*l) )/b)
*/
ll a=p[id].a,b=p[id].b,c=p[id].c;
(ans+=atcoder::floor_sum(x1-x0+1,b,-a,c-a*x0))%=MOD;
}
cout<<ans<<endl;
}
int main(){
ll T;
cin>>T;
while(T--){
clr();
solve();
}
return 0;
}
思路是求下凸包,然后用类欧和交点坐标求出具体下面有几个点