#include <iostream>
#include <complex>
#include <vector>
#include <algorithm>
#include <functional>
#include <iomanip>

using namespace std;

template<typename T> bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
template<typename T> bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }

// 実数
using Real = double;
// 点
using Point = complex<Real>;
const Real EPS = 1e-10, PI = acos(-1);

// 実数同士の比較
inline bool eq(Real a, Real b) { return fabs(b - a) < EPS; }

Point operator*(const Point& p, const Real& d) {
    return Point(real(p) * d, imag(p) * d);
}

// 点の入力
istream& operator>>(istream& is, Point& p) {
    Real a, b;
    is >> a >> b;
    p = Point(a, b);
    return is;
}

//// 点の出力
//ostream &operator<<(ostream &os, Point &p) {
//  os << fixed << setprecision(10) << p.real() << " " << p.imag();
//}

// 点 p を反時計回りに theta 回転
Point rotate(Real theta, const Point& p) {
    return Point(cos(theta) * p.real() - sin(theta) * p.imag(), sin(theta) * p.real() + cos(theta) * p.imag());
}

// ラジアンを度数に変換
Real radian_to_degree(Real r) {
    return (r * 180.0 / PI);
}

// 度数をラジアンに変換
Real degree_to_radian(Real d) {
    return (d * PI / 180.0);
}

// a-b-c の角度のうち小さい方を返す
Real get_angle(const Point& a, const Point& b, const Point& c) {
    const Point v(b - a), w(c - a);
    Real alpha = atan2(v.imag(), v.real()), beta = atan2(w.imag(), w.real());
    if (alpha > beta) swap(alpha, beta);
    Real theta = (beta - alpha);
    return min(theta, 2 * acos(-1) - theta);
}

// ソート x座標が小さい順に並べる x座標が同じならy座標が小さい順
namespace std {
    bool operator<(const Point& a, const Point& b) {
        return !eq(a.real(), b.real()) ? a.real() < b.real() : a.imag() < b.imag();
    }
}

// 2点を通る直線
struct Line {
    Point a, b;

    Line() = default;

    Line(Point a, Point b) : a(a), b(b) {}

    Line(Real A, Real B, Real C) // Ax + By = C
    {
        if (eq(A, 0)) a = Point(0, C / B), b = Point(1, C / B);
        else if (eq(B, 0)) b = Point(C / A, 0), b = Point(C / A, 1);
        else a = Point(0, C / B), b = Point(C / A, 0);
    }

    friend ostream& operator<<(ostream& os, Line& p) {
        return os << p.a << " to " << p.b;
    }

    friend istream& operator>>(istream& is, Line& a) {
        return is >> a.a >> a.b;
    }
};

// 2点を結ぶ線分
struct Segment : Line {
    Segment() = default;
    Segment(Point a, Point b) : Line(a, b) {}
};


// 円
struct Circle {
    // 中心
    Point p;
    // 半径
    Real r;

    Circle() = default;

    Circle(Point p, Real r) : p(p), r(r) {}
};

// 点集合
using Points = vector< Point >;
// ポリゴン 反時計回り
using Polygon = vector< Point >;   // 注意!! 凸多角形は反時計回りに与える.(保証されない場合は面積が負なら reverse をかける)
// 線分集合
using Segments = vector< Segment >;
// 直線集合
using Lines = vector< Line >;
// 円集合
using Circles = vector< Circle >;

// 外積
Real cross(const Point& a, const Point& b) {
    return real(a) * imag(b) - imag(a) * real(b);
}

// 内積
Real dot(const Point& a, const Point& b) {
    return real(a) * real(b) + imag(a) * imag(b);
}

// 点の回転方向
//          +1
//          
//  +2   a   0   b  -2
//
//          -1
// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_C&lang=jp
int ccw(const Point& a, Point b, Point c) {
    b = b - a, c = c - a;
    if (cross(b, c) > EPS) return +1;  // "COUNTER_CLOCKWISE"
    if (cross(b, c) < -EPS) return -1; // "CLOCKWISE"
    if (dot(b, c) < 0) return +2;      // "ONLINE_BACK"
    if (norm(b) < norm(c)) return -2;  // "ONLINE_FRONT"
    return 0;                         // "ON_SEGMENT"
}

// 線分同士の交差判定
// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_B
bool intersect(const Segment& s, const Segment& t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

// 直線同士の交点を返す (交差することが要請されるのかな (事前にintersect を呼べばいい))
Point crosspoint(const Line& l, const Line& m) {
    Real A = cross(l.b - l.a, m.b - m.a);
    Real B = cross(l.b - l.a, l.b - m.a);
    if (eq(abs(A), 0.0) && eq(abs(B), 0.0)) return m.a;
    return m.a + (m.b - m.a) * B / (A + 1e-18);
}

// 線分同士の交点を返す (交差することが要請されるのかな (事前にintersect を呼べばいい))
// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_C
Point crosspoint(const Segment& l, const Segment& m) {
    return crosspoint(Line(l), Line(m));
}

Real CalcDist(const Segment& s, const Point& p) {
    double t = dot(s.b - s.a, p - s.a) / norm(s.b - s.a);
    Point c = s.a + (s.b - s.a) * t;
    Real res = 1000000.0;
    if (t > -EPS && t < 1.0 + EPS) return sqrt(norm(p - c));
    chmin(res, sqrt(norm(p - s.b)));
    chmin(res, sqrt(norm(p - s.a)));
    return res;
}

Real CalcDist(const Segment& a, const Segment& b) {
    return min({CalcDist(a, b.a), CalcDist(a, b.b), CalcDist(b, a.a), CalcDist(b, a.b)});
}

int InPolygon(Point& p, const Polygon& pol) {
    int n = pol.size();

    bool is_in = false;
    for(int i = 0; i < n; ++i) {
        Point a = pol[i] - p;
        Point b = pol[(i + 1) % n] - p;

        //　辺上にあるか
        if (eq(cross(a, b), 0) && dot(a, b) < EPS) return 1;
        // 交わっているか
        if (a.imag() < b.imag()) swap(a, b);
        if (a.imag() > EPS && b.imag() < EPS && cross(a, b) > EPS) is_in = !is_in;
    }

    return (is_in) ? 2 : 0;
}

bool CmpX(const Point& lhs, const Point& rhs) {
    if (lhs.real() != rhs.real()) return lhs.real() < rhs.real();
    return lhs.imag() < rhs.imag();
}

Polygon ConvexHull(vector<Point>& points) {
    int n = points.size();
    sort(points.begin(), points.end(), CmpX);

    int k = 0;
    vector<Point> qs(n * 2);

    // 下側凸包を作成
    for (int i = 0; i < n; ++i) {
        // 凸じゃなくなった
        while (k >= 2 && cross(qs[k - 1] - qs[k - 2], points[i] - qs[k - 2]) < -EPS) --k;
        qs[k++] = points[i];
    }

    // 上側凸包を作成
    for (int i = n - 2, tmp = k; i >= 0; --i) {
        while (k > tmp && cross(qs[k - 1] - qs[k - 2], points[i] - qs[k - 2]) < -EPS) --k;
        qs[k++] = points[i];
    }

    // 作った
    qs.resize(k - 1);
    return qs;
}

Real CalcDist(vector<Segment>& a, vector<Segment>& b) {

    Real ret = 1000000.0;

    // 線分同士の距離
    for (auto& segA : a) {
        for (auto& segB : b) {
            if (intersect(segA, segB)) return 0.0;
            chmin(ret, CalcDist(segA, segB));
        }
    }

    return ret;
}

struct Info {
    Segment seg;
    int type;

    Info() = default;
    Info(Segment seg, int type) : seg(seg), type(type) {}
};

int main() {

    int query;
    cin >> query;
    vector<int> ans(query);

    for (int i = 0; i < query; ++i) {
        Point a, b;
        cin >> a >> b;

        Segment train(a, b);

        int n;
        cin >> n;

        vector<Info> stations;

        for (int j = 0; j < n; ++j) {
            Point s, t;
            cin >> s >> t;
            int o, l;
            cin >> o >> l;
            Segment seg(s, t);
            if (intersect(seg, train)) {
                if (l == 0) o = 1 - o;
                stations.emplace_back(seg, o);
            }
        }

        if (stations.size() == 0) {
            ans[i] = 0;
            continue;
        }

        // 駅の始点からの距離が近い順にソート
        sort(stations.begin(), stations.end(), [&](Info& lhs, Info& rhs) {
            return norm(crosspoint(lhs.seg, train) - train.a) < norm(crosspoint(rhs.seg, train) - train.a);
            });

        int res = 0;
        int prev_type = stations[0].type;
        for (int j = 1; j < stations.size(); ++j) {
            Info& info = stations[j];
            if (info.type != prev_type) {
                prev_type = info.type;  
                ++res;
            }
        }
        ans[i] = res;
    }

    for (auto res : ans) cout << res << endl;
}


Measured memory_bytes: 3096