Problem:
Problem G:
Longest Chain
Let us compare two triples
a = (x
a
, y
a
, z
a
)
and
b = (x
b
, y
b
, z
b
)
by a partial order ∠ defined as follows.
a
∠
b
⇔
x
a
<
x
b
and
y
a
<
y
b
and
z
a
<
z
b
Your mission is to find, in the given set of triples, the longest ascending series
a
1
∠
a
2
∠ ...  ∠
a
k
.
Input
The input is a sequence of datasets, each specifying a set of triples formatted as follows.
m
n
A
B
x
1
y
1
z
1
x
2
y
2
z
2
...
x
m
y
m
z
m
Here,
m
,
n
,
A
and
B
in the first line, and all of
x
i
,
y
i
and
z
i
(
i
= 1, . . . ,
m
) in the following lines are non-negative integers.
Each dataset specifies a set of
m + n
triples. The triples
p
1
through
p
m
are explicitly specified in the dataset, the
i
-th triple
p
i
being (
x
i
, y
i
, z
i
)
. The remaining
n
triples are specified by parameters
A
and
B
given to the following generator routine.
int a = A, b = B, C = ~(1<<31), M = (1<<16)-1;
int r() {
  a = 36969 * (a & M) + (a >> 16);
  b = 18000 * (b & M) + (b >> 16);
  return (C & ((a << 16) + b)) % 1000000;
}
Repeated 3
n
calls of
r()
defined as above yield values of
x
m+1
,
y
m+1
,
z
m+1
,
x
m+2
,
y
m+2
,
z
m+2
, ...,
x
m+n
,
y
m+n
, and
z
m+n
, in this order.
You can assume that 1 ≤
m + n
≤ 3 × 10
5
, 1 ≤
A,B
≤ 2
16
, and 0 ≤
x
k
, y
k
, z
k
< 10
6
for 1 ≤
k
≤
m + n
.
The input ends with a line containing four zeros. The total of
m + n
for all the datasets does not exceed 2 × 10
6
.
Output
For each dataset, output the length of the longest ascending series of triples in the specified set. If
p
i
1
∠
p
i
2
∠ ... ∠
p
i
k
is the longest, the answer should be
k
.
Sample Input
6 0 1 1
0 0 0
0 2 2
1 1 1
2 0 2
2 2 0
2 2 2
5 0 1 1
0 0 0
1 1 1
2 2 2
3 3 3
4 4 4
10 0 1 1
3 0 0
2 1 0
2 0 1
1 2 0
1 1 1
1 0 2
0 3 0
0 2 1
0 1 2
0 0 3
0 10 1 1
0 0 0 0
Output for the Sample Input
3
5
1
3

Submitted solutions:

code_snippet: #include<map>
#include<set>
#include<queue>
#include<cctype>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<algorithm>
typedef long long LL;
#define MAXN 300010
int A, B, C = ~(1<<31), M = (1<<16)-1;
int myRand() {
  A = 36969 * (A & M) + (A >> 16);
  B = 18000 * (B & M) + (B >> 16);
  return (C & ((A << 16) + B)) % 1000000;
}
int N, zn, z[MAXN], f[MAXN], max[MAXN];
struct V {
	int x, y, z;
	bool operator < (const V &t) const {
		if(x != t.x) {
			return x < t.x;
		}
		return y > t.y;
	}
}v[MAXN];
struct T {
	int id, x, y, z;
	bool operator < (const T &t) const {
		if(y != t.y) {
			return y < t.y;
		}
		if(x != t.x) {
			return x > t.x;
		}
		return z > t.z;
	}
}t[MAXN];
int query(int x) {
	int ans = 0;
	for(int i = x; i > 0; i -= i & -i) {
		ans = std::max(ans, max[i]);
	}
	return ans;
}
void update(int x, int v) {
	for(int i = x; i <= zn; i += i & -i) {
		max[i] = std::max(max[i], v);
	}
}
void clear(int x) {
	for(int i = x; i <= zn; i += i & -i) {
		max[i] = 0;
	}
}
void cdq(int x, int y) {
	if(x == y) {
		return ;
	}
	int mid = (x + y) >> 1;
	cdq(x, mid);
	for(int i = x; i <= y; i ++) {
		t[i].id = i;
		t[i].x = v[i].x, t[i].y = v[i].y, t[i].z = v[i].z;
	}
	std::sort(t + x, t + y + 1);
	for(int i = x; i <= y; i ++) {
		if(t[i].id <= mid) {
			update(t[i].z, f[t[i].id]);
		} else {
			f[t[i].id] = std::max(f[t[i].id], query(t[i].z - 1) + 1);
		}
	}
	for(int i = x; i <= y; i ++) {
		if(t[i].id <= mid) {
			clear(t[i].z);
		}
	}
	cdq(mid + 1, y);
}
int main() {
	//freopen("test.in", "rb", stdin);
	int m;
	while(scanf("%d%d%d%d", &N, &m, &A, &B), N + m > 0) {
		for(int i = 0; i < N; i ++) {
			scanf("%d%d%d", &v[i].x, &v[i].y, &v[i].z);
		}
		for(int i = 0; i < m; i ++) {
			v[N].x = myRand();
			v[N].y = myRand();
			v[N].z = myRand();
			++ N;
		}
		std::sort(v, v + N);
		for(int i = 0; i < N; i ++) {
			z[i] = v[i].z;
		}
		std::sort(z, z + N);
		zn = std::unique(z, z + N) - z;
		for(int i = 0; i < N; i ++) {
			v[i].z = std::lower_bound(z, z + zn, v[i].z) - z + 1;
		}
		for(int i = 0; i < N; i ++) {
			f[i] = 1;
		}
		cdq(0, N - 1);
		int ans = 0;
		for(int i = 0; i < N; i ++) {
			ans = std::max(ans, f[i]);
		}
		printf("%d\n", ans);
	}
	return 0;
}
accuracy: 1
time_ms: 1710
memory_kb: 14748
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i, a, b) for(ll i = a; i < b; i++)
#define all(x) (x).begin(), (x).end()

struct FenwickTree {
    int n;
    vector<int> data;
    FenwickTree() = default;
    FenwickTree(int n) : n(n), data(n+1) {}

    int fold(int i) const {
        int ret = 0;
        for(;i>0;i-=i&-i) ret=max(ret,data[i]);
        return ret;
    }
    void update(int i, int x) {
        for(++i; i<=n; i+=i&-i) data[i]=max(data[i],x);
    }

};

struct SegTree2D {
    int size;
    vector<int> xs;
    vector<vector<int>> ys;
    vector<FenwickTree> seg;

    int getx(int x) const {
        return lower_bound(all(xs), x)-xs.begin();
    }
    int gety(int k, int y) const {
        return lower_bound(all(ys[k]), y) - ys[k].begin();
    }

    SegTree2D(const vector<pair<int,int>>& pts){
        for (auto[x,y]:pts){
            xs.push_back(x);
        }
        sort(all(xs));
        xs.erase(unique(all(xs)), xs.end());

        const int n =xs.size();
        size=1;
        while(size < n)size<<=1;
        ys.resize(2*size);
        seg.resize(2*size);

        for (auto[x,y]:pts){
            ys[size+getx(x)].push_back(y);
        }

        for(int i=size+n-1; i>0;--i){
            if (i>=size){
                sort(all(ys[i]));
            }else{
                merge(all(ys[2*i]), all(ys[2*i+1]), back_inserter(ys[i]));
            }
            ys[i].erase(unique(all(ys[i])), ys[i].end());
        }
        rep(i,1,size+n){
            seg[i]=FenwickTree(ys[i].size());
        }
    }

    void update(int x, int y, int val){
        int kx=getx(x);
        kx +=size;
        int ky=gety(kx,y);
        seg[kx].update(ky,val);
        while(kx>>=1){
            ky=gety(kx,y);
            // int kl=gety(2*kx,y), kr=gety(2*kx+1,y);
            // int vl=kl < ys[2*kx].size()&&ys[2*kx][kl]==y ? seg[2*kx][kl] : 0;
            // int vr=kr < ys[2*kx+1].size()&&ys[2*kx+1][kr]==y ? seg[2*kx+1][kr] : 0;
            seg[kx].update(ky, val);
        }
    }

    int fold(int tx, int ty) const {
        int ret = 0;
        for (int l = size, r=size+getx(tx); l < r; l >>= 1, r>>=1) {
            if (r&1){
                --r;
                ret = max(ret, seg[r].fold(gety(r, ty)));
            }
        }
        return ret;
    }

};

int main() {
    const int M = 1e6+10;
    vector<vector<pair<int,int>>> pts(M);

    while (true) {
        int n, m, A, B;
        cin >> m >> n >> A >> B;
        if (m + n == 0) break;

        int a = A, b = B, C = ~(1<<31), M = (1<<16)-1;

        auto r = [&]() {
            a = 36969 * (a & M) + (a >> 16);
            b = 18000 * (b & M) + (b >> 16);
            return (C & ((a << 16) + b)) % 1000000;
        };

        vector<int> xs;
        vector<pair<int,int>> yz;

        rep(i,0,m){
            int x,y,z;
            cin>>x>>y>>z;
            pts[x].push_back({y, z});
            yz.push_back({y,z});
            xs.push_back(x);
        }

        rep(_,0,n){
            int x=r();
            int y=r();
            int z=r();
            pts[x].push_back({y,z});
            yz.push_back({y,z});
            xs.push_back(x);
        }

        sort(all(xs));
        xs.erase(unique(all(xs)), xs.end());

        SegTree2D seg(yz);

        int ans = 0;

        for(auto x:xs){
            vector<int> res;
            for(auto [y,z]:pts[x]){
                res.push_back(seg.fold(y,z)+1);
                ans=max(ans,res.back());
            }
            int k=0;
            for(auto[y,z]:pts[x]){
                seg.update(y,z,res[k++]);
            }
            pts[x].clear();
        }

        cout << ans << "\n";
        cout << flush;
    }
}
accuracy: 1
time_ms: 5370
memory_kb: 168640
final_rank: 20

code_snippet: #line 2 "cp-library/src/cp-template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull  = unsigned long long;
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; }
template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y :           x / y); }
template < class T, class U > T floor(T x, U y) { return (x > 0 ?           x / y : (x - y + 1) / y); }
int popcnt(i32 x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }

#line 2 "cp-library/src/utility/rep_itr.hpp"
template < class T > struct itr_rep {
    T i, d;
    constexpr itr_rep(const T i) noexcept : i(i), d(1) {}
    constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {}
    void operator++() noexcept { i += d; }
    constexpr int operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; }
};

template < class T > struct rep {
    const itr_rep< T > s, t;
    constexpr rep(const T t) noexcept : s(0), t(t) {}
    constexpr rep(const T s, const T t) noexcept : s(s), t(t) {}
    constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};

template < class T > struct revrep {
    const itr_rep < T > s, t;
    constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {}
    constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {}
    constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};
#line 3 "cp-library/src/utility/io.hpp"

/* 128bit integer */
istream& operator>>(istream& is, i128& x) {
    std::string s; is >> s;
    int pm = (s[0] == '-');
    x = 0;
    for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0');
    if(pm) x *= -1;
    return is;
}
ostream& operator<<(ostream& os, const i128& x) {
    if(x == 0) return os << '0';
    i128 y = x;
    if(y < 0) { os << '-'; y *= -1; }
    std::vector<int> ny;
    while(y > 0) { ny.push_back(y % 10); y /= 10; }
    for(int i : revrep(ny.size())) os << ny[i];
    return os;
}

template < class S, class T > istream& operator>>(istream& is,       std::pair< S, T >& x) { is >> x.first        >> x.second; return is; }
template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; }

namespace scanner {
    struct sca {
        template < class T > operator T() {
            T s; std::cin >> s; return s;
        }
    };
    struct vec {
        int n;
        vec(int n) : n(n) {}
        template < class T > operator std::vector< T >() {
            std::vector< T > v(n);
            for(T& x : v) std::cin >> x;
            return v;
        }
    };
    struct mat {
        int h, w;
        mat(int h, int w) : h(h), w(w) {}
        template < class T > operator std::vector< std::vector< T > >() {
            std::vector m(h, std::vector< T >(w));
            for(std::vector< T >& v : m) for(T& x : v) std::cin >> x;
            return m;
        }
    };
    struct speedup {
        speedup() {
            std::cin.tie(0);
            std::ios::sync_with_stdio(0);
        }
    } speedup_instance;
}
scanner::sca in() { return scanner::sca(); }
scanner::vec in(int n) { return scanner::vec(n); }
scanner::mat in(int h, int w) { return scanner::mat(h, w); }

namespace printer {
    void precision(int d) { std::cout << std::fixed << std::setprecision(d); }
    void flush() { std::cout.flush(); }
}

template < class T >
ostream& operator<<(ostream& os, const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; }
    return os;
}

int print() { std::cout << '\n'; return 0; }
template < class head, class... tail > int print(head&& h, tail&&... t) {
    std::cout << h; if(sizeof...(tail)) std::cout << ' ';
    return print(std::forward<tail>(t)...);
}
template < class T > int print_n(const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) std::cout << a[i] << "\n";
    return 0;
}


#line 2 "cp-library/src/utility/key_val.hpp"

template < class K, class V >
struct key_val {
    K key; V val;
    key_val() {}
    key_val(K key, V val) : key(key), val(val) {}
    template < std::size_t Index >
    std::tuple_element_t< Index, key_val >& get() {
        if constexpr (Index == 0) return key;
        if constexpr (Index == 1) return val;
    }
};

namespace std {

template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {};
template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; };
template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; };

}
#line 2 "cp-library/src/utility/vec_op.hpp"
template < class T > key_val< int, T > max_of(const vector< T >& a) {
    int i = std::max_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class T > key_val< int, T > min_of(const vector< T >& a) {
    int i = std::min_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class S, class T > S sum_of(const vector< T >& a) {
    S sum = 0;
    for(const T x : a) sum += x;
    return sum;
}
template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) {
    vector< S > res(R - L, S(0));
    for(const T x : a) res[x - L] += 1;
    return res;
}
template < class S, class T > struct prefix_sum {
    vector< S > s;
    prefix_sum(const vector< T >& a) : s(a) {
        s.insert(s.begin(), S(0));
        for(int i : rep(a.size())) s[i + 1] += s[i];
    }
    // [L, R)
    S sum(int L, int R) { return s[R] - s[L]; }
};
#line 3 "cp-library/src/utility/heap.hpp"

template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >;
template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >;

#line 27 "cp-library/src/cp-template.hpp"

#line 1 "cp-library/src/algorithm/bin_search.hpp"
template < class T, class F >
T bin_search(T ok, T ng, F f) {
    while(abs(ng - ok) > 1) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

template < class T, class F >
T bin_search_real(T ok, T ng, F f, int step = 80) {
    while(step--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
#line 2 "cp-library/src/algorithm/argsort.hpp"

template < class T > std::vector< int > argsort(const std::vector< T > &a) {
    std::vector< int > ids((int)a.size());
    std::iota(ids.begin(), ids.end(), 0);
    std::sort(ids.begin(), ids.end(), [&](int i, int j) {
        return a[i] < a[j] || (a[i] == a[j] && i < j);
    });
    return ids;
}
#line 1 "macro.hpp"
namespace macro {

using size_type = int;
template < class container > void  sort(container& a) { std::sort(std:: begin(a), std:: end(a)); }
template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); }
template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); }
template < class container > void unique(container& a) {
    std::sort(std::begin(a), std::end(a));
    a.erase(std::unique(std::begin(a), std::end(a)), std::end(a));
}
template < class container > container  sorted(const container& a) { container b = a;  sort(b); return std::move(b); }
template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); }
template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); }
template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); }
template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); }
template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); }

const std::vector<std::pair<size_type, size_type>> dir4 = { {+1,  0}, {-1,  0}, { 0, +1}, { 0, -1} };
const std::vector<std::pair<size_type, size_type>> dir8 = { {-1, -1}, {-1,  0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1,  0}, {+1, +1} };

#ifdef _DEBUG
#define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl
#else
#define debug(x)
#endif

template < class container > void concat(container& a, const container& b) {
    a.insert(std::end(a), std::begin(b), std::end(b));
}
std::vector<size_type> iota(const size_type n) {
    std::vector<size_type> I(n);
    std::iota(std::begin(I), std::end(I), 0);
    return I;
}
template < class container > std::vector<size_type> sort_idx(const container& a) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); });
    return I;
}
template < class container, class compare > std::vector<size_type> sort_idx(const container& a, const compare& cmp) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); });
    return std::move(I);
}

struct grid {
    using size_type = int;
    size_type H, W;
    grid(const size_type H, const size_type W) : H(H), W(W) {}
    bool contains(const size_type i, const size_type j) {
        return 0 <= i and i < H and 0 <= j and j < W;
    }
};

using f64 = long double;

} // namespace macro

using namespace macro;
#line 3 "A.cpp"

int solve(int m, int n, int A, int B) {
    vector<int> x(m), y(m), z(m);
    for(int i : rep(m)) x[i] = in(), y[i] = in(), z[i] = in();
    {
        int a = A, b = B, C = ~(1 << 31), M = (1 << 16) - 1;
        auto r = [&]() {
            a = 36969 * (a & M) + (a >> 16);
            b = 18000 * (b & M) + (b >> 16);
            return (C & ((a << 16) + b)) % 1000000;
        };
        for(int i : rep(n)) {
            x.push_back(r());
            y.push_back(r());
            z.push_back(r());
        }
        n = m + n;
    }

    vector<map<int,int>> dp; // lis
    for(int i : sort_idx(iota(n), [&](int i, int j) {
        if(z[i] != z[j]) return z[i] < z[j];
        if(x[i] != x[j]) return x[i] > x[j];
                         return y[i] > y[j];
    })) {
        const int len = dp.size();
        int p = 1 + bin_search(-1, len, [&](int p) {
            // exist? * < (x, y)
            auto it = dp[p].lower_bound(x[i]);
            return it != dp[p].begin() and prev(it)->second < y[i];
        });

        // insert (x, y) to dp[p]
        if(p == len) {
            dp.push_back({{x[i], y[i]}});
        } else {
            // erase * >= (x, y)
            auto it = dp[p].lower_bound(x[i]);
            while(it != dp[p].end() and it->second >= y[i]) it = dp[p].erase(it);
            if(not(it != dp[p].begin() and prev(it)->second <= y[i])) dp[p].insert({x[i], y[i]});
        }
    }
    return dp.size();
}

int main() {
    while(true) {
        int m = in(), n = in(), A = in(), B = in();
        if(make_tuple(m, n, A, B) == make_tuple(0, 0, 0, 0)) return 0;
        print(solve(m, n, A, B));
    }
}
accuracy: 1
time_ms: 780
memory_kb: 15696
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, n) for (int i = 0; i < (n); i++)
#define per(i, n) for (int i = (n)-1; i >= 0; i--)
#define rep2(i, l, r) for (int i = (l); i < (r); i++)
#define per2(i, l, r) for (int i = (r)-1; i >= (l); i--)
#define each(e, x) for (auto &e : x)
#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define rall(x) rbegin(x), rend(x)
#define eb emplace_back
#define TT template <typename T>
#define MM << ' ' <<
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

TT bool chmin(T &x, T y) { return x > y ? (x = y, true) : false; }
TT bool chmax(T &x, T y) { return x < y ? (x = y, true) : false; }

TT using minheap = priority_queue<T, vector<T>, greater<T>>;
TT using maxheap = priority_queue<T>;

TT void print(vector<T> v, T x = 0) {
    int n = sz(v);
    rep(i, n) cout << v[i] + x << (i == n - 1 ? '\n' : ' ');
    if (n == 0) cout << '\n';
}

TT void printn(vector<T> v, T x = 0) {
    int n = sz(v);
    rep(i, n) cout << v[i] + x << '\n';
}

TT void rearrange(vector<T> &v) {
    sort(all(v));
    v.erase(unique(all(v)), end(v));
}

TT int lb(vector<T> &v, T x) { return lower_bound(all(v), x) - begin(v); }
TT int ub(vector<T> &v, T x) { return upper_bound(all(v), x) - begin(v); }

const int inf = (1 << 30) - 1;
const ll INF = (1LL << 60) - 1;

struct io_setup {
    io_setup() {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        cout << fixed << setprecision(15);
    }
} io_setup;

template <typename T>
T f(T x, T y) {
    return max(x, y);
}

template <typename T>
struct BIT {
    int n;
    vector<T> a;

    BIT(vector<T> v) : n(sz(v)) {
        a.assign(n + 1, 0);
        copy(all(v), begin(a) + 1);
        for (int i = 2; i <= n; i <<= 1) {
            for (int j = i; j <= n; j += i) a[j] = f(a[j], a[j - i / 2]);
        }
    }

    BIT(int n, T x) : BIT(vector<T>(n, x)) {}

    void add(int i, T x) {
        for (i++; i <= n; i += (i & -i)) a[i] = f(a[i], x);
    }

    T sum(int i) {
        T ret = 0;
        for (; i > 0; i -= (i & -i)) ret = f(ret, a[i]);
        return ret;
    }
};

template <typename T, typename C>
struct BIT2D {
    int n;
    vector<C> xs;
    vector<pair<C, C>> allPoints;
    vector<vector<C>> ys;
    vector<BIT<T>> bits;

    BIT2D() {}

    void insert(C x, C y) {
        xs.eb(x);
        allPoints.eb(x, y);
    }

    void build() {
        rearrange(xs);
        n = sz(xs);
        ys.resize(n + 1);
        for (auto [x, y] : allPoints) {
            int i = lb(xs, x);
            for (i++; i <= n; i += (i & -i)) ys[i].eb(y);
        }
        rep(i, n + 1) {
            rearrange(ys[i]);
            bits.eb(sz(ys[i]), 0);
        }
    }

    void add(C x, C y, T a) {
        int i = lb(xs, x);
        for (i++; i <= n; i += (i & -i)) {
            int j = lb(ys[i], y);
            bits[i].add(j, a);
        }
    }

    T sum(C x, C y) {
        int i = lb(xs, x);
        T ret = 0;
        for (; i > 0; i -= (i & -i)) {
            int j = lb(ys[i], y);
            ret = f(ret, bits[i].sum(j));
        }
        return ret;
    }
};

using ull = unsigned long long;

void solve() {
    int M, N;
    int A, B;
    cin >> M >> N >> A >> B;

    if (N == 0 && M == 0) exit(0);

    vector<int> x(M), y(M), z(M);
    rep(i, M) cin >> x[i] >> y[i] >> z[i];

    int a = A, b = B;
    auto rand = [&]() {
        int C = ~(1 << 31), M = (1 << 16) - 1;
        a = 36969 * (a & M) + (a >> 16);
        b = 18000 * (b & M) + (b >> 16);
        return (C & ((a << 16) + b)) % 1000000;
    };

    rep(i, 3 * N) {
        int t = rand();
        (i % 3 == 0 ? x : i % 3 == 1 ? y : z).eb(t);
    }

    N += M;

    // rep(i, N) cout << x[i] MM y[i] MM z[i] << '\n';

    const int MAX = 1000000;

    BIT2D<int, int> bit;
    vector<vector<int>> ids(MAX);

    rep(i, N) {
        ids[z[i]].eb(i);
        bit.insert(x[i], y[i]);
    }
    bit.build();

    vector<int> dp(N, -inf);

    rep(i, MAX) {
        each(e, ids[i]) {
            dp[e] = bit.sum(x[e], y[e]) + 1; //
        }
        each(e, ids[i]) {
            bit.add(x[e], y[e], dp[e]); //
        }
    }

    cout << *max_element(all(dp)) << '\n';
}

int main() {
    while (true) solve(); //
}
accuracy: 1
time_ms: 4100
memory_kb: 109136
final_rank: 16

code_snippet: #include <iostream>
#include <tuple>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

class RangeMax {
public:
	int size_ = 1;
	vector<int> dat;

	void init(int sz) {
		while (size_ <= sz) size_ *= 2;
		dat.resize(size_ * 2, -1000000);
	}

	void update(int pos, int x) {
		pos += size_;
		dat[pos] = x;
		while (pos >= 2) {
			pos >>= 1;
			dat[pos] = max(dat[pos * 2], dat[pos * 2 + 1]);
		}
	}

	int query_(int l, int r, int a, int b, int u) {
		if (l <= a && b <= r) return dat[u];
		if (r <= a || b <= l) return -(1 << 30);
		int v1 = query_(l, r, a, (a + b) / 2, u * 2);
		int v2 = query_(l, r, (a + b) / 2, b, u * 2 + 1);
		return max(v1, v2);
	}

	int query(int l, int r) {
		return query_(l, r, 0, size_, 1);
	}
};

// 誤読で 20 分溶かした．
int M, N, A, B;
int X[300009], Y[300009], Z[300009];
int Bar[300009];
int dp[300009];
vector<int> LX, LY, LZ;
RangeMax W;

void Generate() {
	int a = A, b = B, C = ~(1 << 31), MM = (1 << 16) - 1;
	for (int i = 0; i < 3 * N; i++) {
		a = 36969 * (a & MM) + (a >> 16);
		b = 18000 * (b & MM) + (b >> 16);
		int val = (C & ((a << 16) + b)) % 1000000;
		if (i % 3 == 0) X[M + i / 3] = val;
		if (i % 3 == 1) Y[M + i / 3] = val;
		if (i % 3 == 2) Z[M + i / 3] = val;
	}
}

void dfs(int cl, int cr) {
	if (cr - cl == 1) return;
	int cm = (cl + cr) / 2;
	int pl = Bar[cl];
	int pm = Bar[cm];
	int pr = Bar[cr];

	// Recursion 1
	dfs(cl, cm);

	// Initialize
	vector<pair<int, int>> List;
	for (int i = pl; i < pm; i++) List.push_back(make_pair(Y[i], i));
	for (int i = pm; i < pr; i++) List.push_back(make_pair(Y[i], -i));
	sort(List.begin(), List.end());

	// Main Query
	for (int i = 0; i < List.size(); i++) {
		int idx = abs(List[i].second);
		if (idx < pm) {
			W.update(Z[idx], max(W.dat[Z[idx] + W.size_], dp[idx]));
		}
		if (idx >= pm) {
			dp[idx] = max(dp[idx], W.query(0, Z[idx]) + 1);
		}
	}

	// Reset
	for (int i = 0; i < List.size(); i++) {
		int idx = abs(List[i].second);
		if (idx < pm) W.update(Z[idx], -1000000);
	}

	// Recursion 2
	dfs(cm, cr);
}

int Solve() {
	// Step 1. Compression
	LX.clear();
	LY.clear();
	LZ.clear();
	for (int i = 0; i < M + N; i++) LX.push_back(X[i]);
	for (int i = 0; i < M + N; i++) LY.push_back(Y[i]);
	for (int i = 0; i < M + N; i++) LZ.push_back(Z[i]);
	sort(LX.begin(), LX.end()); LX.erase(unique(LX.begin(), LX.end()), LX.end());
	sort(LY.begin(), LY.end()); LY.erase(unique(LY.begin(), LY.end()), LY.end());
	sort(LZ.begin(), LZ.end()); LZ.erase(unique(LZ.begin(), LZ.end()), LZ.end());
	for (int i = 0; i < M + N; i++) X[i] = lower_bound(LX.begin(), LX.end(), X[i]) - LX.begin();
	for (int i = 0; i < M + N; i++) Y[i] = lower_bound(LY.begin(), LY.end(), Y[i]) - LY.begin();
	for (int i = 0; i < M + N; i++) Z[i] = lower_bound(LZ.begin(), LZ.end(), Z[i]) - LZ.begin();
	W.init(LZ.size() + 2);

	// Step 2. Sorting
	vector<tuple<int, int, int>> tup;
	for (int i = 0; i < M + N; i++) tup.push_back(make_tuple(X[i], Y[i], Z[i]));
	sort(tup.begin(), tup.end());
	for (int i = 0; i < M + N; i++) {
		X[i] = get<0>(tup[i]);
		Y[i] = get<1>(tup[i]);
		Z[i] = get<2>(tup[i]);
	}
	for (int i = 0; i <= LX.size(); i++) Bar[i] = 0;
	for (int i = 0; i < M + N; i++) Bar[X[i] + 1] += 1;
	for (int i = 1; i <= LX.size(); i++) Bar[i] += Bar[i - 1];

	// Step 3. Divide and Conquer
	for (int i = 0; i < M + N; i++) dp[i] = 1;
	dfs(0, LX.size());
	int maxn = 0;
	for (int i = 0; i < M + N; i++) maxn = max(maxn, dp[i]);
	return maxn;
}

int main() {
	while (true) {
		cin >> M >> N >> A >> B;
		if (M + N + A + B == 0) break;
		for (int i = 0; i < M; i++) cin >> X[i] >> Y[i] >> Z[i];
		Generate();
		cout << Solve() << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 3630
memory_kb: 28636
final_rank: 11

code_snippet: #ifndef HIDDEN_IN_VS // 折りたたみ用

// 警告の抑制
#define _CRT_SECURE_NO_WARNINGS

// ライブラリの読み込み
#include <bits/stdc++.h>
using namespace std;

// 型名の短縮
using ll = long long; // -2^63 ～ 2^63 = 9 * 10^18（int は -2^31 ～ 2^31 = 2 * 10^9）
using pii = pair<int, int>;	using pll = pair<ll, ll>;	using pil = pair<int, ll>;	using pli = pair<ll, int>;
using vi = vector<int>;		using vvi = vector<vi>;		using vvvi = vector<vvi>;
using vl = vector<ll>;		using vvl = vector<vl>;		using vvvl = vector<vvl>;
using vb = vector<bool>;	using vvb = vector<vb>;		using vvvb = vector<vvb>;
using vc = vector<char>;	using vvc = vector<vc>;		using vvvc = vector<vvc>;
using vd = vector<double>;	using vvd = vector<vd>;		using vvvd = vector<vvd>;
template <class T> using priority_queue_rev = priority_queue<T, vector<T>, greater<T>>;
using Graph = vvi;

// 定数の定義
const double PI = acos(-1);
const vi DX = { 1, 0, -1, 0 }; // 4 近傍（下，右，上，左）
const vi DY = { 0, 1, 0, -1 };
int INF = 1001001001; ll INFL = 4004004004004004004LL;
double EPS = 1e-12;

// 入出力高速化
struct fast_io { fast_io() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(18); } } fastIOtmp;

// 汎用マクロの定義
#define all(a) (a).begin(), (a).end()
#define sz(x) ((int)(x).size())
#define lbpos(a, x) (int)distance((a).begin(), std::lower_bound(all(a), x))
#define ubpos(a, x) (int)distance((a).begin(), std::upper_bound(all(a), x))
#define Yes(b) {cout << ((b) ? "Yes\n" : "No\n");}
#define rep(i, n) for(int i = 0, i##_len = int(n); i < i##_len; ++i) // 0 から n-1 まで昇順
#define repi(i, s, t) for(int i = int(s), i##_end = int(t); i <= i##_end; ++i) // s から t まで昇順
#define repir(i, s, t) for(int i = int(s), i##_end = int(t); i >= i##_end; --i) // s から t まで降順
#define repe(v, a) for(const auto& v : (a)) // a の全要素（変更不可能）
#define repea(v, a) for(auto& v : (a)) // a の全要素（変更可能）
#define repb(set, d) for(int set = 0; set < (1 << int(d)); ++set) // d ビット全探索（昇順）
#define repp(a) sort(all(a)); for(bool a##_perm = true; a##_perm; a##_perm = next_permutation(all(a))) // a の順列全て（昇順）
#define smod(n, m) ((((n) % (m)) + (m)) % (m)) // 非負mod
#define uniq(a) {sort(all(a)); (a).erase(unique(all(a)), (a).end());} // 重複除去
#define EXIT(a) {cout << (a) << endl; exit(0);} // 強制終了

// 汎用関数の定義
template <class T> inline ll pow(T n, int k) { ll v = 1; rep(i, k) v *= n; return v; }
template <class T> inline bool chmax(T& M, const T& x) { if (M < x) { M = x; return true; } return false; } // 最大値を更新（更新されたら true を返す）
template <class T> inline bool chmin(T& m, const T& x) { if (m > x) { m = x; return true; } return false; } // 最小値を更新（更新されたら true を返す）

// 演算子オーバーロード
template <class T, class U> inline istream& operator>>(istream& is, pair<T, U>& p) { is >> p.first >> p.second; return is; }
template <class T> inline istream& operator>>(istream& is, vector<T>& v) { repea(x, v) is >> x; return is; }
template <class T> inline vector<T>& operator--(vector<T>& v) { repea(x, v) --x; return v; }
template <class T> inline vector<T>& operator++(vector<T>& v) { repea(x, v) ++x; return v; }

// 手元環境（Visual Studio）
#ifdef _MSC_VER
#include "local.hpp"
// 提出用（gcc）
#else
inline int popcount(int n) { return __builtin_popcount(n); }
inline int popcount(ll n) { return __builtin_popcountll(n); }
inline int lsb(int n) { return n != 0 ? __builtin_ctz(n) : -1; }
inline int lsb(ll n) { return n != 0 ? __builtin_ctzll(n) : -1; }
inline int msb(int n) { return n != 0 ? (31 - __builtin_clz(n)) : -1; }
inline int msb(ll n) { return n != 0 ? (63 - __builtin_clzll(n)) : -1; }
#define gcd __gcd
#define dump(...)
#define dumpel(v)
#define dump_list(v)
#define dump_list2D(v)
#define input_from_file(f)
#define output_to_file(f)
#define Assert(b) { if (!(b)) while (1) cout << "OLE"; }
#endif

#endif // 折りたたみ用


////--------------AtCoder 専用--------------
//#include <atcoder/all>
//using namespace atcoder;
//
////using mint = modint1000000007;
//using mint = modint998244353;
////using mint = modint; // mint::set_mod(m);
//
//istream& operator>>(istream& is, mint& x) { ll x_; is >> x_; x = x_; return is; }
//ostream& operator<<(ostream& os, const mint& x) { os << x.val(); return os; }
//using vm = vector<mint>; using vvm = vector<vm>; using vvvm = vector<vvm>;
////----------------------------------------


//【狭義単調な点列】
/*
* Monotonous_points<T>(bool y_greater = true, T inf = max(T)/2) : O(1)
*	空で初期化する．x 座標は狭義単調増加で，y 座標は y_greater=true[false] なら狭義単調増加[減少]とする．
* 
* void insert(T x, T y) : ならし O(log n)
*	点 (x, y) を挿入し，それにより単調性に違反する点は全て削除する．
*
* bool find_LL(T x, T y, bool strict = true) : O(log n)
*	x' < x かつ y' < y なる点 (x', y') が存在するかを返す（strict=false なら等号も許す）
*
* bool find_LG(T x, T y, bool strict = true) : O(log n)
*	x' < x かつ y' > y なる点 (x', y') が存在するかを返す（strict=false なら等号も許す）
*
* bool find_GL(T x, T y, bool strict = true) : O(log n)
*	x' > x かつ y' < y なる点 (x', y') が存在するかを返す（strict=false なら等号も許す）
* 
* bool find_GG(T x, T y, bool strict = true) : O(log n)
*	x' > x かつ y' > y なる点 (x', y') が存在するかを返す（strict=false なら等号も許す）
* 
* pTT lower_bound(T x) : O(log n)
*	x' >= x なる x 座標が最小の点 (x', y') を返す（なければ (inf, inf[ninf])）
* 
* pTT upper_bound(T x) : O(log n)
*	x' > x なる x 座標が最小の点 (x', y') を返す（なければ (inf, inf[ninf])）
* 
* pTT lower_bound_rev(T x) : O(log n)
*	x' <= x なる x 座標が最大の点 (x', y') を返す（なければ (ninf, ninf[inf])）
* 
* pTT upper_bound_rev(T x) : O(log n)
*	x' < x なる x 座標が最大の点 (x', y') を返す（なければ (ninf, ninf[inf])）
*/
template <class T>
struct Monotonous_points {
	// 参考 : https://topcoder-g-hatena-ne-jp.jag-icpc.org/skyaozora/20141216.html

	bool y_greater;
	T inf;

	// x, y 両座標ともに狭義単調増加な点列
	map<T, T> x_to_y;

	// 空で初期化
	Monotonous_points(bool y_greater = true, T inf_ = -1) : y_greater(y_greater) {
		inf = (inf_ == -1 ? numeric_limits<T>::max() / 2 : inf_);

		// 番兵を挿入しておく．
		if (y_greater) { x_to_y[-inf] = -inf; x_to_y[inf] = inf; }
		else { x_to_y[-inf] = inf; x_to_y[inf] = -inf; }
	}

	// 点 (x, y) を挿入し，単調性に違反する点は全て削除する．
	void insert(T x, T y) {
		// verify : https://atcoder.jp/contests/abc283/tasks/abc283_f

		// x <= x' なる最小の x' を指すイテレータを得る．
		auto it = x_to_y.lower_bound(x);

		// x' から昇順に，y' <= y[ y' >= y ] である限り要素を削除する．
		if (y_greater) {
			while (true) {
				if (it->second > y) break;
				it = x_to_y.erase(it);
			}
		}
		else {
			while (true) {
				if (it->second < y) break;
				it = x_to_y.erase(it);
			}
		}

		// x' から降順に，y' >= y[ y' <= y ] である限り要素を削除する．
		if (y_greater) {
			while (true) {
				it = prev(it);
				if (it->second < y) break;
				it = x_to_y.erase(it);
			}
		}
		else {
			while (true) {
				it = prev(it);
				if (it->second > y) break;
				it = x_to_y.erase(it);
			}
		}

		// 点 (x, y) を挿入する．
		x_to_y[x] = y;
	}

	// x' < x かつ y' < y なる点が存在するかを返す（strict=false なら等号も許す）
	bool find_LL(T x, T y, bool strict = true) {
		if (strict) {
			T y2 = prev(x_to_y.lower_bound(x))->second;
			return y2 != -inf && y2 < y;
		}
		else {
			T y2 = prev(x_to_y.upper_bound(x))->second;
			return y2 != -inf && y2 <= y;
		}
	}

	// x' < x かつ y' > y なる点が存在するかを返す（strict=false なら等号も許す）
	bool find_LG(T x, T y, bool strict = true) {
		if (strict) {
			T y2 = prev(x_to_y.lower_bound(x))->second;
			return y2 != inf && y2 > y;
		}
		else {
			T y2 = prev(x_to_y.upper_bound(x))->second;
			return y2 != inf && y2 >= y;
		}
	}

	// x' > x かつ y' < y なる点が存在するかを返す（strict=false なら等号も許す）
	bool find_GL(T x, T y, bool strict = true) {
		if (strict) {
			T y2 = x_to_y.upper_bound(x)->second;
			return y2 != -inf && y2 < y;
		}
		else {
			T y2 = x_to_y.lower_bound(x)->second;
			return y2 != -inf && y2 <= y;
		}
	}

	// x' > x かつ y' > y なる点が存在するかを返す（strict=false なら等号も許す）
	bool find_GG(T x, T y, bool strict = true) {
		if (strict) {
			T y2 = x_to_y.upper_bound(x)->second;
			return y2 != inf && y2 > y;
		}
		else {
			T y2 = x_to_y.lower_bound(x)->second;
			return y2 != inf && y2 >= y;
		}
	}

	// x' >= x なる x 座標が最小の点 (x', y') を返す（なければ (inf, inf[ninf])）
	pair<T, T> lower_bound(T x) {
		return *x_to_y.lower_bound(x);
	}

	// x' > x なる x 座標が最小の点 (x', y') を返す（なければ (inf, inf[ninf])）
	pair<T, T> upper_bound(T x) {
		return *x_to_y.upper_bound(x);
	}

	// x' <= x なる x 座標が最大の点 (x', y') を返す（なければ (ninf, ninf[inf])）
	pair<T, T> lower_bound_rev(T x) {
		return *prev(x_to_y.upper_bound(x));
	}

	// x' < x なる x 座標が最大の点 (x', y') を返す（なければ (ninf, ninf[inf])）
	pair<T, T> upper_bound_rev(T x) {
		return *prev(x_to_y.lower_bound(x));
	}

#ifdef _MSC_VER
	friend ostream& operator<<(ostream& os, const Monotonous_points& mp) {
		repe(p, mp.x_to_y) if (abs(p.first) != mp.inf) os << p << " ";
		return os;
	}
#endif
}; 


//【めぐる式二分探索】O(log|ok - ng|)
/*
* 条件 okQ() を満たす要素 ok と満たさない要素 ng との境界を二分探索する．
* 境界に隣り合うような条件を満たす要素（ok 側）の位置を返す．
*/
template <typename T>
T meguru_search(T ok, T ng, function<bool(T)>& okQ) {
	// 参考 : https://twitter.com/meguru_comp/status/697008509376835584
	// verify : https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/all/ALDS1_4_D

	// 境界が決定するまで
	while (abs(ok - ng) > 1) {
		// 区間の中間
		T mid = (ok + ng) / 2;

		// 中間が OK かどうかに応じて区間を縮小する．
		if (okQ(mid)) ok = mid;
		else ng = mid;
	}
	return ok;

	/* okQ の定義の雛形
	using T = ll;
	function<bool(T)> okQ = [&](T x) {
		return true || false;
	};
	*/
}


//【最長増加部分列（二次元）】O(n (log n)^2)
/*
* 数列 a[0..n), b[0..n) について，添字の増加列 t_0 < ... < t_(k-1) で，
*		∀i∈[0..k-1), a[t_i] < a[t_(i+1)] かつ b[t_i] < b[t_(i+1)]
* を満たすものの長さ k の最大値を返す．
*
* 利用：【狭義単調な点列】，【めぐる式二分探索】
*/
template <class T>
int longest_increasing_subsequence_2D(const vector<T>& a, const vector<T>& b) {
	// 参考 : https://topcoder-g-hatena-ne-jp.jag-icpc.org/skyaozora/20141216.html
	// verify : https://onlinejudge.u-aizu.ac.jp/problems/1341

	int n = sz(a);

	// ps[j] : その要素を末尾にもつ長さ j の増加部分列が存在するような点（ps[0] は使わない）
	vector<Monotonous_points<T>> ps(1);

	rep(i, n) {
		// j : (a[i], b[i]) を末尾に持つ増加部分列の最大長
		function<bool(int)> okQ = [&](int j) { return ps[j].find_LL(a[i], b[i]); };
		int j = meguru_search(0, sz(ps), okQ) + 1;

		// 点 (a[i], b[i]) を挿入する．
		if (j >= sz(ps)) ps.push_back(Monotonous_points<T>(false));
		if (!ps[j].find_LL(a[i], b[i], false)) ps[j].insert(a[i], b[i]);

		dump(i); dump(ps);
	}

	return sz(ps) - 1;
}


int a, b, C = ~(1 << 31), M = (1 << 16) - 1;
int r() {
	a = 36969 * (a & M) + (a >> 16);
	b = 18000 * (b & M) + (b >> 16);
	return (C & ((a << 16) + b)) % 1000000;
}


int solve(int N, vi x, vi y, vi z) {
	vector<tuple<int, int, int>> xyz(N);
	rep(i, N) xyz[i] = { -x[i], y[i], z[i] };
	sort(all(xyz), greater<tuple<int, int, int>>());

	rep(i, N) tie(x[i], y[i], z[i]) = xyz[i];
	dump(y); dump(z);

	return longest_increasing_subsequence_2D(y, z);
}


//【最長パス】O(|V| + |E|)
/*
* DAG g の頂点 s からの最長パスの長さを len[s] に格納し len を返す．
*/
vi longest_path(const Graph& g) {
	// verify : https://atcoder.jp/contests/dp/tasks/dp_g

	int n = sz(g);

	// len[s] : 頂点 s からの最長パスの長さ
	vi len(n);
	vb seen(n);

	function<int(int)> dfs = [&](int s) {
		if (seen[s]) return len[s];
		seen[s] = true;
		len[s] = 0;

		// s → t と進む場合
		repe(t, g[s]) chmax(len[s], dfs(t) + 1);

		return len[s];
	};

	// 各頂点 s についての情報を計算する．
	rep(s, n) if (!seen[s]) dfs(s);

	return len;
}


int naive(int N, vi x, vi y, vi z) {
	Graph g(N);

	rep(i, N) rep(j, N) {
		if (x[i] < x[j] && y[i] < y[j] && z[i] < z[j]) {
			g[i].push_back(j);
		}
	}

	auto len = longest_path(g);

	return *max_element(all(len)) + 1;
}


void bug_find() {
#ifdef _MSC_VER
	// 合わない入力例を見つける．

	mt19937_64 mt;
	mt.seed((int)time(NULL));
	uniform_int_distribution<ll> rnd(0LL, 1LL << 62);

	mute_dump = true;

	rep(hoge, 1000) {
		int n = 50;
		vi x(n), y(n), z(n);
		rep(i, n) {
			x[i] = rnd(mt) % 10;
			y[i] = rnd(mt) % 10;
			z[i] = rnd(mt) % 10;
		}

		auto res_naive = naive(n, x, y, z);
		auto res_solve = solve(n, x, y, z);

		if (res_naive != res_solve) {
			cout << "----------error!----------" << endl;
			cout << "input:" << endl;
			cout << x << endl;
			cout << y << endl;
			cout << z << endl;
			cout << "results:" << endl;
			cout << res_naive << endl;
			cout << res_solve << endl;
			cout << "--------------------------" << endl;
		}
	}

	mute_dump = false;
	exit(0);
#endif
}
/*
----------error!----------
input:
0 2 8 3 6
4 2 2 0 0
2 0 2 0 9
results:
2
1
--------------------------
*/


int main() {
	input_from_file("input.txt");
//	output_to_file("output.txt");

	bug_find();

	while (1) {
		int m, n;
		cin >> m >> n >> a >> b;
		dump(m, n, a, b);

		if (m == 0 && n == 0) return 0;

		vi x(m + n), y(m + n), z(m + n);
		rep(i, m) cin >> x[i] >> y[i] >> z[i];
		rep(i, n) { x[m + i] = r(); y[m + i] = r(); z[m + i] = r(); }

		dump(naive(m + n, x, y, z));
		cout << solve(m + n, x, y, z) << endl;
	}
}
accuracy: 1
time_ms: 850
memory_kb: 25092
final_rank: 7

code_snippet: #ifndef HIDDEN_IN_VS // 折りたたみ用

// 警告の抑制
#define _CRT_SECURE_NO_WARNINGS

// ライブラリの読み込み
#include <bits/stdc++.h>
using namespace std;

// 型名の短縮
using ll = long long; // -2^63 ～ 2^63 = 9 * 10^18（int は -2^31 ～ 2^31 = 2 * 10^9）
using pii = pair<int, int>;	using pll = pair<ll, ll>;	using pil = pair<int, ll>;	using pli = pair<ll, int>;
using vi = vector<int>;		using vvi = vector<vi>;		using vvvi = vector<vvi>;
using vl = vector<ll>;		using vvl = vector<vl>;		using vvvl = vector<vvl>;
using vb = vector<bool>;	using vvb = vector<vb>;		using vvvb = vector<vvb>;
using vc = vector<char>;	using vvc = vector<vc>;		using vvvc = vector<vvc>;
using vd = vector<double>;	using vvd = vector<vd>;		using vvvd = vector<vvd>;
template <class T> using priority_queue_rev = priority_queue<T, vector<T>, greater<T>>;
using Graph = vvi;

// 定数の定義
const double PI = acos(-1);
const vi DX = { 1, 0, -1, 0 }; // 4 近傍（下，右，上，左）
const vi DY = { 0, 1, 0, -1 };
int INF = 1001001001; ll INFL = 4004004004004004004LL;
double EPS = 1e-12;

// 入出力高速化
struct fast_io { fast_io() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(18); } } fastIOtmp;

// 汎用マクロの定義
#define all(a) (a).begin(), (a).end()
#define sz(x) ((int)(x).size())
#define lbpos(a, x) (int)distance((a).begin(), std::lower_bound(all(a), x))
#define ubpos(a, x) (int)distance((a).begin(), std::upper_bound(all(a), x))
#define Yes(b) {cout << ((b) ? "Yes\n" : "No\n");}
#define rep(i, n) for(int i = 0, i##_len = int(n); i < i##_len; ++i) // 0 から n-1 まで昇順
#define repi(i, s, t) for(int i = int(s), i##_end = int(t); i <= i##_end; ++i) // s から t まで昇順
#define repir(i, s, t) for(int i = int(s), i##_end = int(t); i >= i##_end; --i) // s から t まで降順
#define repe(v, a) for(const auto& v : (a)) // a の全要素（変更不可能）
#define repea(v, a) for(auto& v : (a)) // a の全要素（変更可能）
#define repb(set, d) for(int set = 0; set < (1 << int(d)); ++set) // d ビット全探索（昇順）
#define repp(a) sort(all(a)); for(bool a##_perm = true; a##_perm; a##_perm = next_permutation(all(a))) // a の順列全て（昇順）
#define smod(n, m) ((((n) % (m)) + (m)) % (m)) // 非負mod
#define uniq(a) {sort(all(a)); (a).erase(unique(all(a)), (a).end());} // 重複除去
#define EXIT(a) {cout << (a) << endl; exit(0);} // 強制終了

// 汎用関数の定義
template <class T> inline ll pow(T n, int k) { ll v = 1; rep(i, k) v *= n; return v; }
template <class T> inline bool chmax(T& M, const T& x) { if (M < x) { M = x; return true; } return false; } // 最大値を更新（更新されたら true を返す）
template <class T> inline bool chmin(T& m, const T& x) { if (m > x) { m = x; return true; } return false; } // 最小値を更新（更新されたら true を返す）

// 演算子オーバーロード
template <class T, class U> inline istream& operator>>(istream& is, pair<T, U>& p) { is >> p.first >> p.second; return is; }
template <class T> inline istream& operator>>(istream& is, vector<T>& v) { repea(x, v) is >> x; return is; }
template <class T> inline vector<T>& operator--(vector<T>& v) { repea(x, v) --x; return v; }
template <class T> inline vector<T>& operator++(vector<T>& v) { repea(x, v) ++x; return v; }

// 手元環境（Visual Studio）
#ifdef _MSC_VER
#include "local.hpp"
// 提出用（gcc）
#else
inline int popcount(int n) { return __builtin_popcount(n); }
inline int popcount(ll n) { return __builtin_popcountll(n); }
inline int lsb(int n) { return n != 0 ? __builtin_ctz(n) : -1; }
inline int lsb(ll n) { return n != 0 ? __builtin_ctzll(n) : -1; }
inline int msb(int n) { return n != 0 ? (31 - __builtin_clz(n)) : -1; }
inline int msb(ll n) { return n != 0 ? (63 - __builtin_clzll(n)) : -1; }
#define gcd __gcd
#define dump(...)
#define dumpel(v)
#define dump_list(v)
#define dump_list2D(v)
#define input_from_file(f)
#define output_to_file(f)
#define Assert(b) { if (!(b)) while (1) cout << "OLE"; }
#endif

#endif // 折りたたみ用


////--------------AtCoder 専用--------------
//#include <atcoder/all>
//using namespace atcoder;
//
////using mint = modint1000000007;
//using mint = modint998244353;
////using mint = modint; // mint::set_mod(m);
//
//istream& operator>>(istream& is, mint& x) { ll x_; is >> x_; x = x_; return is; }
//ostream& operator<<(ostream& os, const mint& x) { os << x.val(); return os; }
//using vm = vector<mint>; using vvm = vector<vm>; using vvvm = vector<vvm>;
////----------------------------------------


//【めぐる式二分探索】O(log|ok - ng|)
/*
* 条件 okQ() を満たす要素 ok と満たさない要素 ng との境界を二分探索する．
* 境界に隣り合うような条件を満たす要素（ok 側）の位置を返す．
*/
template <typename T>
T meguru_search(T ok, T ng, function<bool(T)>& okQ) {
	// 参考 : https://twitter.com/meguru_comp/status/697008509376835584
	// verify : https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/all/ALDS1_4_D

	// 境界が決定するまで
	while (abs(ok - ng) > 1) {
		// 区間の中間
		T mid = (ok + ng) / 2;

		// 中間が OK かどうかに応じて区間を縮小する．
		if (okQ(mid)) ok = mid;
		else ng = mid;
	}
	return ok;

	/* okQ の定義の雛形
	using T = ll;
	function<bool(T)> okQ = [&](T x) {
		return true || false;
	};
	*/
}


//【狭義単調な点列】
/*
* Monotonous_points<T>() : O(1)
*	空で初期化する．
* 
* void insert(T x, T y) : ならし O(log n)
*	点 (x, y) を挿入し，x <= x' かつ y <= y' なる点 (x', y') は全て削除する．
* 
* bool find(T x, T y) : O(log n)
*	x' < x かつ y' < y なる点が存在するかを返す．
*/
template <class T>
class Monotonous_points {
	// 参考 : https://topcoder-g-hatena-ne-jp.jag-icpc.org/skyaozora/20141216.html

	// x 座標狭義昇順に保持した点のリスト（y 座標は狭義降順）
	map<T, T> x_to_y;

public:
	// 空で初期化
	Monotonous_points() {}

	// 点 (x, y) を挿入し，x <= x' かつ y <= y' なる点 (x', y') は全て削除する．
	void insert(T x, T y) {
		// x <= x' なる最小の x' を指すイテレータを得る．
		auto it = x_to_y.lower_bound(x);

		// x' から昇順に，y <= y' である限り要素を削除する．
		while (it != x_to_y.end()) {
			if (it->second < y) break;

			it = x_to_y.erase(it);
		}

		// 点 (x, y) を挿入する．
		if (it == x_to_y.end() || it->first != x) x_to_y[x] = y;
	}

	// x' < x かつ y' < y なる点が存在するかを返す．
	bool find(T x, T y) {
		// x <= x' なる最小の x' を指すイテレータを得る．
		auto it = x_to_y.lower_bound(x);

		// その直前の要素が条件を満たさないなら他の要素もだめ．
		return it != x_to_y.begin() && prev(it)->second < y;
	}

#ifdef _MSC_VER
	friend ostream& operator<<(ostream& os, const Monotonous_points& mp) {
		repe(p, mp.x_to_y) os << p << " ";
		return os;
	}
#endif
};


//【最長増加部分列（二次元）】O(n (log n)^2)
/*
* 数列 a[0..n), b[0..n) について，添字の増加列 t_0 < ... < t_(k-1) で，
*		∀i∈[0..k-1), a[t_i] < a[t_(i+1)] かつ b[t_i] < b[t_(i+1)]
* を満たすものの長さ k の最大値を返す．
* 
* 利用：【狭義単調な点列】，【めぐる式二分探索】
*/
template <class T>
int longest_increasing_subsequence_2D(const vector<T>& a, const vector<T>& b) {
	// 参考 : https://topcoder-g-hatena-ne-jp.jag-icpc.org/skyaozora/20141216.html

	int n = sz(a);

	// ps[j] : その要素を末尾にもつ長さ j の増加部分列が存在するような点（ps[0] は使わない）
	vector<Monotonous_points<T>> ps(1);

	rep(i, n) {
		// j : (a[i], b[i]) を末尾に持つ増加部分列の最大長
		function<bool(int)> okQ = [&](int j) { return ps[j].find(a[i], b[i]); };
		int j = meguru_search(0, sz(ps), okQ) + 1;

		// 点 (a[i], b[i]) を挿入する．
		if (j >= sz(ps)) ps.push_back(Monotonous_points<T>());
		ps[j].insert(a[i], b[i]);

		dump(i); dump(ps);
	}

	return sz(ps) - 1;
}


int a, b, C = ~(1 << 31), M = (1 << 16) - 1;
int r() {
	a = 36969 * (a & M) + (a >> 16);
	b = 18000 * (b & M) + (b >> 16);
	return (C & ((a << 16) + b)) % 1000000;
}


int solve(int N, vi x, vi y, vi z) {
	vector<tuple<int, int, int>> xyz(N);
	rep(i, N) xyz[i] = { -x[i], y[i], z[i] };
	sort(all(xyz), greater<tuple<int, int, int>>());

	rep(i, N) tie(x[i], y[i], z[i]) = xyz[i];
	dump(y); dump(z);

	return longest_increasing_subsequence_2D(y, z);
}


//【最長パス】O(|V| + |E|)
/*
* DAG g の頂点 s からの最長パスの長さを len[s] に格納し len を返す．
*/
vi longest_path(const Graph& g) {
	// verify : https://atcoder.jp/contests/dp/tasks/dp_g

	int n = sz(g);

	// len[s] : 頂点 s からの最長パスの長さ
	vi len(n);
	vb seen(n);

	function<int(int)> dfs = [&](int s) {
		if (seen[s]) return len[s];
		seen[s] = true;
		len[s] = 0;

		// s → t と進む場合
		repe(t, g[s]) chmax(len[s], dfs(t) + 1);

		return len[s];
	};

	// 各頂点 s についての情報を計算する．
	rep(s, n) if (!seen[s]) dfs(s);

	return len;
}


int naive(int N, vi x, vi y, vi z) {
	Graph g(N);

	rep(i, N) rep(j, N) {
		if (x[i] < x[j] && y[i] < y[j] && z[i] < z[j]) {
			g[i].push_back(j);
		}
	}

	auto len = longest_path(g);

	return *max_element(all(len)) + 1;
}


void bug_find() {
#ifdef _MSC_VER
	// 合わない入力例を見つける．

	mt19937_64 mt;
	mt.seed((int)time(NULL));
	uniform_int_distribution<ll> rnd(0LL, 1LL << 62);

	mute_dump = true;

	rep(hoge, 1000) {
		int n = 50;
		vi x(n), y(n), z(n);
		rep(i, n) {
			x[i] = rnd(mt) % 10;
			y[i] = rnd(mt) % 10;
			z[i] = rnd(mt) % 10;
		}

		auto res_naive = naive(n, x, y, z);
		auto res_solve = solve(n, x, y, z);

		if (res_naive != res_solve) {
			cout << "----------error!----------" << endl;
			cout << "input:" << endl;
			cout << x << endl;
			cout << y << endl;
			cout << z << endl;
			cout << "results:" << endl;
			cout << res_naive << endl;
			cout << res_solve << endl;
			cout << "--------------------------" << endl;
		}
	}

	mute_dump = false;
	exit(0);
#endif
}
/*
----------error!----------
input:
0 2 8 3 6
4 2 2 0 0
2 0 2 0 9
results:
2
1
--------------------------
*/


int main() {
	input_from_file("input.txt");
//	output_to_file("output.txt");

	bug_find();

	while (1) {
		int m, n;
		cin >> m >> n >> a >> b;
		dump(m, n, a, b);

		if (m == 0 && n == 0) return 0;

		vi x(m + n), y(m + n), z(m + n);
		rep(i, m) cin >> x[i] >> y[i] >> z[i];
		rep(i, n) { x[m + i] = r(); y[m + i] = r(); z[m + i] = r(); }

		dump(naive(m + n, x, y, z));
		cout << solve(m + n, x, y, z) << endl;
	}
}
accuracy: 1
time_ms: 720
memory_kb: 19752
final_rank: 5

code_snippet: #include "bits/stdc++.h"
using namespace std;
using namespace std::chrono;
typedef long long int llint;
typedef long double lldo;
#define mp make_pair
#define mt make_tuple
#define pub push_back
#define puf push_front
#define pob pop_back
#define pof pop_front
#define fir first
#define sec second
#define res resize
#define ins insert
#define era erase
#define REP(i, n) for(int i = 0;i < (n);i++)
/*cout<<fixed<<setprecision(20);cin.tie(0);ios::sync_with_stdio(false);*/
const int mod=1000000007;
const llint inf=2.19e15+1;
const long double pai=3.141592653589793238462643383279502884197;
const long double eps=1e-10;
template <class T,class U>bool chmin(T& a,U b){if(a>b){a=b;return true;}return false;}
template <class T,class U>bool chmax(T& a,U b){if(a<b){a=b;return true;}return false;}
llint gcd(llint a,llint b){if(a%b==0){return b;}else return gcd(b,a%b);}
llint lcm(llint a,llint b){if(a==0){return b;}return a/gcd(a,b)*b;}
template<class T> void SO(T& ve){sort(ve.begin(),ve.end());}
template<class T> void REV(T& ve){reverse(ve.begin(),ve.end());}
template<class T>int LBI(const vector<T>&ar,T in){return lower_bound(ar.begin(),ar.end(),in)-ar.begin();}
template<class T>int UBI(const vector<T>&ar,T in){return upper_bound(ar.begin(),ar.end(),in)-ar.begin();}

template<class T> using V=vector<T>;
template<class T> using VV=vector<V<T>>;
template<class T>struct Fenwick{
	int n;
	V<T> seg;
	Fenwick(int _n=0):n(_n),seg(n+1){}
	void add(int i,int x){
		i++;
		while(i<=n){
			chmax(seg[i],x);
			i+=i&-i;
		}
	}
	T max(int i){
		T s=0;
		while(i>0){
			chmax(s,seg[i]);
			i-=i&-i;
		}
		return s;
	}
};

template<class D,class I>struct Fenwick2D{
	using P=pair<I,I>;
	V<P>points;
	VV<I>ys;
	V<Fenwick<D>>fws;
	int lg,sz;
	Fenwick2D(V<P> _points):points(_points){
		SO(points);
		points.erase(unique(points.begin(),points.end()),points.end());
		int n=int(points.size());
		lg=1;
		while((1<<lg)<n){lg++;}
		sz=1<<lg;
		ys=VV<I>(2*sz);
		for(int i=0;i<n;i++){
			ys[sz+i].pub(points[i].sec);
		}
		for(int i=sz-1;i>=1;i--){
			ys[i]=V<I>(ys[i+i].size()+ys[i+i+1].size());
			merge(ys[i+i].begin(),ys[i+i].end(),ys[i+i+1].begin(),ys[i+i+1].end(),ys[i].begin());
		}
		fws=V<Fenwick<D>>(sz+sz);
		for(int i=1;i<2*sz;i++){
			fws[i]=Fenwick<D>(int(ys[i].size()));
		}
	}
	void add(P p,D x){
		int k=LBI(points,p);
		k+=sz;
		while(k){
			int yid=LBI(ys[k],p.sec);
			fws[k].add(yid,x);
			k>>=1;
		}
	}
	D getmax(int a,int b,I up,int l,int r,int k){
		if(b<=l||r<=a){return 0;}
		if(a<=l&&r<=b){
			int uid=LBI(ys[k],up);
			return fws[k].max(uid);
		}
		int mid=(l+r)/2;
		return max(getmax(a,b,up,l,mid,2*k),getmax(a,b,up,mid,r,2*k+1));
	}
	D getmax(P up){
		int b=LBI(points,mp(up.fir,-mod));
		return getmax(0,b,up.sec,0,sz,1);
	}
};
int a, b , C = ~(1<<31), M = (1<<16)-1;
int rrr() {
  a = 36969 * (a & M) + (a >> 16);
  b = 18000 * (b & M) + (b >> 16);
  return (C & ((a << 16) + b)) % 1000000;
}
int main(void){
	while(-1){
		int m,n,A,B,i;cin>>m>>n>>A>>B;
		if(m+n==0){return 0;}
		vector<tuple<int,int,int>>xyz(n+m);
		a=A;b=B;
		for(i=0;i<m;i++){
			int x,y,z;cin>>x>>y>>z;
			xyz[i]=mt(x,-y,-z);
		}
		for(i=0;i<n;i++){
			int x,y,z;x=rrr();y=rrr();z=rrr();
			xyz[m+i]=mt(x,-y,-z);
		}
		SO(xyz);
		vector<pair<int,int>>yz(n+m);
		for(i=0;i<n+m;i++){
			yz[i]=mp(-get<1>(xyz[i]),-get<2>(xyz[i]));
		}
		Fenwick2D<int,int> segki(yz);
		int ans=0;
		for(i=0;i<n+m;i++){
			int kaz=segki.getmax(yz[i])+1;
			chmax(ans,kaz);
			
			segki.add(yz[i],kaz);
		}
		cout<<ans<<endl;
	}
	return 0;
}
accuracy: 1
time_ms: 5600
memory_kb: 160288
final_rank: 19

code_snippet: #pragma region Macros
#if defined(noimi) && defined(_GLIBCXX_DEBUG) && defined(_GLIBCXX_DEBUG_PEDANTIC)
// #pragma comment(linker, "/stack:200000000")
#include <stdc++.h>
#pragma GCC optimize("O3")
#else
#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #pragma GCC target("popcnt")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2,tune=native")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2")
// #pragma GCC target("avx2")
// #include <bits/stdc++.h>
#include <bits/stdc++.h>
#endif
#include <cstdint>
#include <immintrin.h>
#include <variant>

#ifdef noimi
#define oj_local(a, b) b
#else
#define oj_local(a, b) a
#endif

#define LOCAL if(oj_local(0, 1))
#define OJ if(oj_local(1, 0))

using namespace std;
using ll = long long;
using ull = unsigned long long int;
using i128 = __int128_t;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using ld = long double;
template <typename T> using vc = vector<T>;
template <typename T> using vvc = vector<vc<T>>;
template <typename T> using vvvc = vector<vvc<T>>;
using vi = vc<int>;
using vl = vc<ll>;
using vpi = vc<pii>;
using vpl = vc<pll>;
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
template <typename T> int si(const T &x) { return x.size(); }
template <class T, class S> inline bool chmax(T &a, const S &b) { return (a < b ? a = b, 1 : 0); }
template <class T, class S> inline bool chmin(T &a, const S &b) { return (a > b ? a = b, 1 : 0); }
vi iota(int n) {
    vi a(n);
    return iota(a.begin(), a.end(), 0), a;
}
template <typename T> vi iota(const vector<T> &a, bool greater = false) {
    vi res(a.size());
    iota(res.begin(), res.end(), 0);
    sort(res.begin(), res.end(), [&](int i, int j) {
        if(greater) return a[i] > a[j];
        return a[i] < a[j];
    });
    return res;
}

// macros
#define overload5(a, b, c, d, e, name, ...) name
#define overload4(a, b, c, d, name, ...) name
#define endl '\n'
#define REP0(n) for(ll jidlsjf = 0; jidlsjf < n; ++jidlsjf)
#define REP1(i, n) for(ll i = 0; i < (n); ++i)
#define REP2(i, a, b) for(ll i = (a); i < (b); ++i)
#define REP3(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep(...) overload4(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define per0(n) for(int jidlsjf = 0; jidlsjf < (n); ++jidlsjf)
#define per1(i, n) for(ll i = (n)-1; i >= 0; --i)
#define per2(i, a, b) for(ll i = (a)-1; i >= b; --i)
#define per3(i, a, b, c) for(ll i = (a)-1; i >= (b); i -= (c))
#define per(...) overload4(__VA_ARGS__, per3, per2, per1, per0)(__VA_ARGS__)
#define fore0(a) rep(a.size())
#define fore1(i, a) for(auto &&i : a)
#define fore2(a, b, v) for(auto &&[a, b] : v)
#define fore3(a, b, c, v) for(auto &&[a, b, c] : v)
#define fore4(a, b, c, d, v) for(auto &&[a, b, c, d] : v)
#define fore(...) overload5(__VA_ARGS__, fore4, fore3, fore2, fore1, fore0)(__VA_ARGS__)
#define fi first
#define se second
#define pb push_back
#define ppb pop_back
#define ppf pop_front
#define eb emplace_back
#define drop(s) cout << #s << endl, exit(0)
#define si(c) (int)(c).size()
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define rng(v, l, r) v.begin() + l, v.begin() + r
#define all(c) begin(c), end(c)
#define rall(c) rbegin(c), rend(c)
#define SORT(v) sort(all(v))
#define REV(v) reverse(all(v))
#define UNIQUE(x) SORT(x), x.erase(unique(all(x)), x.end())
template <typename T = ll, typename S> T SUM(const S &v) { return accumulate(all(v), T(0)); }
#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                                                         \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
constexpr pii dx4[4] = {pii{1, 0}, pii{0, 1}, pii{-1, 0}, pii{0, -1}};
constexpr pii dx8[8] = {{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};

namespace yesno_impl {
const string YESNO[2] = {"NO", "YES"};
const string YesNo[2] = {"No", "Yes"};
const string yesno[2] = {"no", "yes"};
const string firstsecond[2] = {"second", "first"};
const string FirstSecond[2] = {"Second", "First"};
const string possiblestr[2] = {"impossible", "possible"};
void YES(bool t = 1) { cout << YESNO[t] << endl; }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { cout << YesNo[t] << endl; }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { cout << yesno[t] << endl; }
void no(bool t = 1) { yes(!t); }
void first(bool t = 1) { cout << firstsecond[t] << endl; }
void First(bool t = 1) { cout << FirstSecond[t] << endl; }
void possible(bool t = 1) { cout << possiblestr[t] << endl; }
}; // namespace yesno_impl
using namespace yesno_impl;

#define INT(...)                                                                                                                                               \
    int __VA_ARGS__;                                                                                                                                           \
    IN(__VA_ARGS__)
#define LL(...)                                                                                                                                                \
    ll __VA_ARGS__;                                                                                                                                            \
    IN(__VA_ARGS__)
#define STR(...)                                                                                                                                               \
    string __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                                                                               \
    char __VA_ARGS__;                                                                                                                                          \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                                                                               \
    double __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define VEC(type, name, size)                                                                                                                                  \
    vector<type> name(size);                                                                                                                                   \
    IN(name)
#define VEC2(type, name1, name2, size)                                                                                                                         \
    vector<type> name1(size), name2(size);                                                                                                                     \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i])
#define VEC3(type, name1, name2, name3, size)                                                                                                                  \
    vector<type> name1(size), name2(size), name3(size);                                                                                                        \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i])
#define VEC4(type, name1, name2, name3, name4, size)                                                                                                           \
    vector<type> name1(size), name2(size), name3(size), name4(size);                                                                                           \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i], name4[i]);
#define VV(type, name, h, w)                                                                                                                                   \
    vector<vector<type>> name(h, vector<type>(w));                                                                                                             \
    IN(name)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &...tail) {
    scan(head);
    IN(tail...);
}

template <typename T, typename S> T ceil(T x, S y) {
    assert(y);
    return (y < 0 ? ceil(-x, -y) : (x > 0 ? (x + y - 1) / y : x / y));
}

template <typename T, typename S> T floor(T x, S y) {
    assert(y);
    return (y < 0 ? floor(-x, -y) : (x > 0 ? x / y : x / y - (x % y == 0 ? 0 : 1)));
}
template <class T> T POW(T x, int n) {
    T res = 1;
    for(; n; n >>= 1, x *= x)
        if(n & 1) res *= x;
    return res;
}
template <class T, class S> T POW(T x, S n, const ll &mod) {
    T res = 1;
    x %= mod;
    for(; n; n >>= 1, x = x * x % mod)
        if(n & 1) res = res * x % mod;
    return res;
}
vector<pll> factor(ll x) {
    vector<pll> ans;
    for(ll i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ans.push_back({i, 1});
            while((x /= i) % i == 0) ans.back().second++;
        }
    if(x != 1) ans.push_back({x, 1});
    return ans;
}
template <class T> vector<T> divisor(T x) {
    vector<T> ans;
    for(T i = 1; i * i <= x; i++)
        if(x % i == 0) {
            ans.pb(i);
            if(i * i != x) ans.pb(x / i);
        }
    return ans;
}
template <typename T> void zip(vector<T> &x) {
    vector<T> y = x;
    UNIQUE(y);
    for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); }
}
template <class S> void fold_in(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void fold_in(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto e : a) v.emplace_back(e);
    fold_in(v, tail...);
}
template <class S> void renumber(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void renumber(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto &&e : a) e = lb(v, e);
    renumber(v, tail...);
}
template <class S, class... Args> vector<S> zip(vector<S> &head, Args &&...args) {
    vector<S> v;
    fold_in(v, head, args...);
    sort(all(v)), v.erase(unique(all(v)), v.end());
    renumber(v, head, args...);
    return v;
}
template <typename T> vector<T> RUI(const vector<T> &v) {
    vector<T> res(v.size() + 1);
    for(int i = 0; i < v.size(); i++) res[i + 1] = res[i] + v[i];
    return res;
}
// 反時計周りに 90 度回転
template <typename T> void rot(vector<vector<T>> &v) {
    if(empty(v)) return;
    int n = v.size(), m = v[0].size();
    vector res(m, vector<T>(n));
    rep(i, n) rep(j, m) res[m - 1 - j][i] = v[i][j];
    v.swap(res);
}
// x in [l, r)
template <class T, class S> bool inc(const T &x, const S &l, const S &r) { return l <= x and x < r; }

// 便利関数
constexpr ll ten(int n) { return n == 0 ? 1 : ten(n - 1) * 10; }
constexpr ll tri(ll n) { return n * (n + 1) / 2; }
// l + ... + r
constexpr ll tri(ll l, ll r) { return (l + r) * (r - l + 1) / 2; }
ll max(int x, ll y) { return max((ll)x, y); }
ll max(ll x, int y) { return max(x, (ll)y); }
int min(int x, ll y) { return min((ll)x, y); }
int min(ll x, int y) { return min(x, (ll)y); }
// bit 演算系
ll pow2(int i) { return 1LL << i; }
int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(ll t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int lowbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int lowbit(ll a) { return a == 0 ? 64 : __builtin_ctzll(a); }
// int allbit(int n) { return (1 << n) - 1; }
constexpr ll mask(int n) { return (1LL << n) - 1; }
// int popcount(signed t) { return __builtin_popcount(t); }
// int popcount(ll t) { return __builtin_popcountll(t); }
int popcount(uint64_t t) { return __builtin_popcountll(t); }
static inline uint64_t popcount64(uint64_t x) {
    uint64_t m1 = 0x5555555555555555ll;
    uint64_t m2 = 0x3333333333333333ll;
    uint64_t m4 = 0x0F0F0F0F0F0F0F0Fll;
    uint64_t h01 = 0x0101010101010101ll;

    x -= (x >> 1) & m1;
    x = (x & m2) + ((x >> 2) & m2);
    x = (x + (x >> 4)) & m4;

    return (x * h01) >> 56;
}
bool ispow2(int i) { return i && (i & -i) == i; }

ll rnd(ll l, ll r) { //[l, r)
#ifdef noimi
    static mt19937_64 gen;
#else
    static mt19937_64 gen(chrono::steady_clock::now().time_since_epoch().count());
#endif
    return uniform_int_distribution<ll>(l, r - 1)(gen);
}
ll rnd(ll n) { return rnd(0, n); }

template <class t> void random_shuffle(vc<t> &a) { rep(i, si(a)) swap(a[i], a[rnd(0, i + 1)]); }

int in() {
    int x;
    cin >> x;
    return x;
}
ll lin() {
    unsigned long long x;
    cin >> x;
    return x;
}

template <class T, class S> pair<T, S> operator-(const pair<T, S> &x) { return pair<T, S>(-x.first, -x.second); }
template <class T, class S> pair<T, S> operator-(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi - y.fi, x.se - y.se); }
template <class T, class S> pair<T, S> operator+(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi + y.fi, x.se + y.se); }
template <class T> pair<T, T> operator&(const pair<T, T> &l, const pair<T, T> &r) { return pair<T, T>(max(l.fi, r.fi), min(l.se, r.se)); }
template <class T, class S> pair<T, S> operator+=(pair<T, S> &l, const pair<T, S> &r) { return l = l + r; }
template <class T, class S> pair<T, S> operator-=(pair<T, S> &l, const pair<T, S> &r) { return l = l - r; }
template <class T> bool intersect(const pair<T, T> &l, const pair<T, T> &r) { return (l.se < r.se ? r.fi < l.se : l.fi < r.se); }

template <typename T> struct edge {
    int from, to;
    T cost;
    int id;
    edge(int to, T cost) : from(-1), to(to), cost(cost) {}
    edge(int from, int to, T cost) : from(from), to(to), cost(cost) {}
    edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {}
    constexpr bool operator<(const edge<T> &rhs) const noexcept { return cost < rhs.cost; }
    edge &operator=(const int &x) {
        to = x;
        return *this;
    }
    operator int() const { return to; }
    friend ostream operator<<(ostream &os, edge &e) { return os << e.to; }
};
template <typename T> using Edges = vector<edge<T>>;

using Tree = vector<vector<int>>;
using Graph = vector<vector<int>>;
template <class T> using Wgraph = vector<vector<edge<T>>>;
Graph getG(int n, int m = -1, bool directed = false, int margin = 1) {
    Tree res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        cin >> a >> b;
        a -= margin, b -= margin;
        res[a].emplace_back(b);
        if(!directed) res[b].emplace_back(a);
    }
    return res;
}
Graph getTreeFromPar(int n, int margin = 1) {
    Graph res(n);
    for(int i = 1; i < n; i++) {
        int a;
        cin >> a;
        res[a - margin].emplace_back(i);
    }
    return res;
}
template <class T> Wgraph<T> getWg(int n, int m = -1, bool directed = false, int margin = 1) {
    Wgraph<T> res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        T c;
        scan(a), scan(b), scan(c);
        a -= margin, b -= margin;
        res[a].emplace_back(b, c);
        if(!directed) res[b].emplace_back(a, c);
    }
    return res;
}
void add(Graph &G, int x, int y) { G[x].eb(y), G[y].eb(x); }
template <class S, class T> void add(Wgraph<S> &G, int x, int y, T c) { G[x].eb(y, c), G[y].eb(x, c); }

#define TEST                                                                                                                                                   \
    INT(testcases);                                                                                                                                            \
    while(testcases--)

istream &operator>>(istream &is, i128 &v) {
    string s;
    is >> s;
    v = 0;
    for(int i = 0; i < (int)s.size(); i++) {
        if(isdigit(s[i])) { v = v * 10 + s[i] - '0'; }
    }
    if(s[0] == '-') { v *= -1; }
    return is;
}

ostream &operator<<(ostream &os, const i128 &v) {
    if(v == 0) { return (os << "0"); }
    i128 num = v;
    if(v < 0) {
        os << '-';
        num = -num;
    }
    string s;
    for(; num > 0; num /= 10) { s.push_back((char)(num % 10) + '0'); }
    reverse(s.begin(), s.end());
    return (os << s);
}
namespace aux {
template <typename T, unsigned N, unsigned L> struct tp {
    static void output(std::ostream &os, const T &v) {
        os << std::get<N>(v) << (&os == &cerr ? ", " : " ");
        tp<T, N + 1, L>::output(os, v);
    }
};
template <typename T, unsigned N> struct tp<T, N, N> {
    static void output(std::ostream &os, const T &v) { os << std::get<N>(v); }
};
} // namespace aux
template <typename... Ts> std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &t) {
    if(&os == &cerr) { os << '('; }
    aux::tp<std::tuple<Ts...>, 0, sizeof...(Ts) - 1>::output(os, t);
    if(&os == &cerr) { os << ')'; }
    return os;
}
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &p) {
    if(&os == &cerr) { return os << "(" << p.first << ", " << p.second << ")"; }
    return os << p.first << " " << p.second;
}
template <class Ch, class Tr, class Container> std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os, const Container &x) {
    bool f = true;
    if(&os == &cerr) os << "[";
    for(auto &y : x) {
        if(&os == &cerr)
            os << (f ? "" : ", ") << y;
        else
            os << (f ? "" : " ") << y;
        f = false;
    }
    if(&os == &cerr) os << "]";
    return os;
}

#ifdef noimi
#undef endl
void debug() { cerr << endl; }
void debug(bool) { cerr << endl; }
template <class Head, class... Tail> void debug(bool is_front, Head head, Tail... tail) {
    if(!is_front) cerr << ", ";
    cerr << head;
    debug(false, tail...);
}

#define dump(args...)                                                                                                                                          \
    {                                                                                                                                                          \
        vector<string> _debug = _split(#args, ',');                                                                                                            \
        err(true, begin(_debug), args);                                                                                                                        \
    }

vector<string> _split(const string &s, char c) {
    vector<string> v;
    stringstream ss(s);
    string x;
    while(getline(ss, x, c)) {
        if(empty(v))
            v.eb(x);
        else {
            bool flag = false;
            for(auto [c, d] : {pair('(', ')'), pair('[', ']'), pair('{', '}')}) {
                if(count(all(v.back()), c) != count(all(v.back()), d)) flag = true;
            }
            if(flag)
                v.back() += "," + x;
            else
                v.eb(x);
        }
    }
    return move(v);
}

void err(bool, vector<string>::iterator) { cerr << endl; }
template <typename T, typename... Args> void err(bool is_front, vector<string>::iterator it, T a, Args... args) {
    if(!is_front) cerr << ", ";
    cerr << it->substr((*it)[0] == ' ', (*it).size()) << " = " << a, err(false, ++it, args...);
}

// #define dump(...) cerr << #__VA_ARGS__ << " : ", debug(true, __VA_ARGS__)
#else
#define dump(...) static_cast<void>(0)
#define dbg(...) static_cast<void>(0)
#endif
void OUT() { cout << endl; }
template <class Head, class... Tail> void OUT(const Head &head, const Tail &...tail) {
    cout << head;
    if(sizeof...(tail)) cout << ' ';
    OUT(tail...);
}

template <typename T> static constexpr T inf = numeric_limits<T>::max() / 2;
template <class T, class S> constexpr pair<T, S> inf<pair<T, S>> = {inf<T>, inf<S>};

template <class F> struct REC {
    F f;
    REC(F &&f_) : f(std::forward<F>(f_)) {}
    template <class... Args> auto operator()(Args &&...args) const { return f(*this, std::forward<Args>(args)...); }
};

template <class S> vector<pair<S, int>> runLength(const vector<S> &v) {
    vector<pair<S, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}
vector<pair<char, int>> runLength(const string &v) {
    vector<pair<char, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}

int toint(const char &c, const char start = 'a') { return c - start; }
int toint(const char &c, const string &chars) { return find(all(chars), c) - begin(chars); }
int alphabets_to_int(const char &c) { return (islower(c) ? c - 'a' : c - 'A' + 26); }
template <typename T> auto toint(const T &v, const char &start = 'a') {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
template <typename T> auto toint(const T &v, const string &start) {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
// a -> 0, A -> 26
template <typename T> auto alphabets_to_int(const T &s) {
    vector<decltype(alphabets_to_int(s[0]))> res;
    res.reserve(s.size());
    for(auto &&e : s) { res.emplace_back(alphabets_to_int(e)); }
    return res;
}

template <class T, class F> T bin_search(T ok, T ng, const F &f) {
    while(abs(ok - ng) > 1) {
        T mid = ok + ng >> 1;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
template <class T, class F> T bin_search_double(T ok, T ng, const F &f, int iter = 80) {
    while(iter--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(11);
    }
} setup_io;

#pragma endregion

int a, b, C, M;
int r() {
    a = 36969 * (a & M) + (a >> 16);
    b = 18000 * (b & M) + (b >> 16);
    return (C & ((a << 16) + b)) % 1000000;
}

int main() {
    rep(1000) {
        INT(m, n, A, B);
        if(!n and !m) exit(0);
        if(m + n > 1000) dump(m, n, A, B);
        VEC3(int, x, y, z, m);
        { a = A, b = B, C = ~(1 << 31), M = (1 << 16) - 1; }

        rep(n) { x.eb(r()), y.eb(r()), z.eb(r()); }

        n += m;

        auto id = iota(n);
        sort(all(id), [&](int i, int j) { return z[i] != z[j] ? z[i] < z[j] : x[i] != x[j] ? x[i] > x[j] : y[i] > y[j]; });

        vector<map<int, int>> dp;
        fore(i, id) {
            int k = bin_search(-1, si(dp), [&](int k) {
                auto it = dp[k].lower_bound(x[i]);
                return it != begin(dp[k]) and prev(it)->se < y[i];
            });
            if(k + 1 < si(dp)) {
                auto &s = dp[k + 1];
                auto it = s.lower_bound(x[i]);
                while(it != end(s) and it->se >= y[i]) { it = s.erase(it); }
                if(it != begin(s) and prev(it)->se <= y[i])
                    continue;
                else
                    s.emplace_hint(it, x[i], y[i]);
            } else {
                dp.eb(map<int, int>{{x[i], y[i]}});
            }
            // dump(dp);
        }

        OUT(si(dp));
    }
}
accuracy: 1
time_ms: 710
memory_kb: 14580
final_rank: 2

code_snippet: #pragma region Macros
#if defined(noimi) && defined(_GLIBCXX_DEBUG) && defined(_GLIBCXX_DEBUG_PEDANTIC)
// #pragma comment(linker, "/stack:200000000")
#include <stdc++.h>
#pragma GCC optimize("O3")
#else
#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #pragma GCC target("popcnt")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2,tune=native")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2")
// #pragma GCC target("avx2")
// #include <bits/stdc++.h>
#include <bits/stdc++.h>
#endif
#include <cstdint>
#include <immintrin.h>
#include <variant>

#ifdef noimi
#define oj_local(a, b) b
#else
#define oj_local(a, b) a
#endif

#define LOCAL if(oj_local(0, 1))
#define OJ if(oj_local(1, 0))

using namespace std;
using ll = long long;
using ull = unsigned long long int;
using i128 = __int128_t;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using ld = long double;
template <typename T> using vc = vector<T>;
template <typename T> using vvc = vector<vc<T>>;
template <typename T> using vvvc = vector<vvc<T>>;
using vi = vc<int>;
using vl = vc<ll>;
using vpi = vc<pii>;
using vpl = vc<pll>;
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
template <typename T> int si(const T &x) { return x.size(); }
template <class T, class S> inline bool chmax(T &a, const S &b) { return (a < b ? a = b, 1 : 0); }
template <class T, class S> inline bool chmin(T &a, const S &b) { return (a > b ? a = b, 1 : 0); }
vi iota(int n) {
    vi a(n);
    return iota(a.begin(), a.end(), 0), a;
}
template <typename T> vi iota(const vector<T> &a, bool greater = false) {
    vi res(a.size());
    iota(res.begin(), res.end(), 0);
    sort(res.begin(), res.end(), [&](int i, int j) {
        if(greater) return a[i] > a[j];
        return a[i] < a[j];
    });
    return res;
}

// macros
#define overload5(a, b, c, d, e, name, ...) name
#define overload4(a, b, c, d, name, ...) name
#define endl '\n'
#define REP0(n) for(ll jidlsjf = 0; jidlsjf < n; ++jidlsjf)
#define REP1(i, n) for(ll i = 0; i < (n); ++i)
#define REP2(i, a, b) for(ll i = (a); i < (b); ++i)
#define REP3(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep(...) overload4(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define per0(n) for(int jidlsjf = 0; jidlsjf < (n); ++jidlsjf)
#define per1(i, n) for(ll i = (n)-1; i >= 0; --i)
#define per2(i, a, b) for(ll i = (a)-1; i >= b; --i)
#define per3(i, a, b, c) for(ll i = (a)-1; i >= (b); i -= (c))
#define per(...) overload4(__VA_ARGS__, per3, per2, per1, per0)(__VA_ARGS__)
#define fore0(a) rep(a.size())
#define fore1(i, a) for(auto &&i : a)
#define fore2(a, b, v) for(auto &&[a, b] : v)
#define fore3(a, b, c, v) for(auto &&[a, b, c] : v)
#define fore4(a, b, c, d, v) for(auto &&[a, b, c, d] : v)
#define fore(...) overload5(__VA_ARGS__, fore4, fore3, fore2, fore1, fore0)(__VA_ARGS__)
#define fi first
#define se second
#define pb push_back
#define ppb pop_back
#define ppf pop_front
#define eb emplace_back
#define drop(s) cout << #s << endl, exit(0)
#define si(c) (int)(c).size()
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define rng(v, l, r) v.begin() + l, v.begin() + r
#define all(c) begin(c), end(c)
#define rall(c) rbegin(c), rend(c)
#define SORT(v) sort(all(v))
#define REV(v) reverse(all(v))
#define UNIQUE(x) SORT(x), x.erase(unique(all(x)), x.end())
template <typename T = ll, typename S> T SUM(const S &v) { return accumulate(all(v), T(0)); }
#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                                                         \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
constexpr pii dx4[4] = {pii{1, 0}, pii{0, 1}, pii{-1, 0}, pii{0, -1}};
constexpr pii dx8[8] = {{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};

namespace yesno_impl {
const string YESNO[2] = {"NO", "YES"};
const string YesNo[2] = {"No", "Yes"};
const string yesno[2] = {"no", "yes"};
const string firstsecond[2] = {"second", "first"};
const string FirstSecond[2] = {"Second", "First"};
const string possiblestr[2] = {"impossible", "possible"};
void YES(bool t = 1) { cout << YESNO[t] << endl; }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { cout << YesNo[t] << endl; }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { cout << yesno[t] << endl; }
void no(bool t = 1) { yes(!t); }
void first(bool t = 1) { cout << firstsecond[t] << endl; }
void First(bool t = 1) { cout << FirstSecond[t] << endl; }
void possible(bool t = 1) { cout << possiblestr[t] << endl; }
}; // namespace yesno_impl
using namespace yesno_impl;

#define INT(...)                                                                                                                                               \
    int __VA_ARGS__;                                                                                                                                           \
    IN(__VA_ARGS__)
#define LL(...)                                                                                                                                                \
    ll __VA_ARGS__;                                                                                                                                            \
    IN(__VA_ARGS__)
#define STR(...)                                                                                                                                               \
    string __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                                                                               \
    char __VA_ARGS__;                                                                                                                                          \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                                                                               \
    double __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define VEC(type, name, size)                                                                                                                                  \
    vector<type> name(size);                                                                                                                                   \
    IN(name)
#define VEC2(type, name1, name2, size)                                                                                                                         \
    vector<type> name1(size), name2(size);                                                                                                                     \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i])
#define VEC3(type, name1, name2, name3, size)                                                                                                                  \
    vector<type> name1(size), name2(size), name3(size);                                                                                                        \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i])
#define VEC4(type, name1, name2, name3, name4, size)                                                                                                           \
    vector<type> name1(size), name2(size), name3(size), name4(size);                                                                                           \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i], name4[i]);
#define VV(type, name, h, w)                                                                                                                                   \
    vector<vector<type>> name(h, vector<type>(w));                                                                                                             \
    IN(name)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &...tail) {
    scan(head);
    IN(tail...);
}

template <typename T, typename S> T ceil(T x, S y) {
    assert(y);
    return (y < 0 ? ceil(-x, -y) : (x > 0 ? (x + y - 1) / y : x / y));
}

template <typename T, typename S> T floor(T x, S y) {
    assert(y);
    return (y < 0 ? floor(-x, -y) : (x > 0 ? x / y : x / y - (x % y == 0 ? 0 : 1)));
}
template <class T> T POW(T x, int n) {
    T res = 1;
    for(; n; n >>= 1, x *= x)
        if(n & 1) res *= x;
    return res;
}
template <class T, class S> T POW(T x, S n, const ll &mod) {
    T res = 1;
    x %= mod;
    for(; n; n >>= 1, x = x * x % mod)
        if(n & 1) res = res * x % mod;
    return res;
}
vector<pll> factor(ll x) {
    vector<pll> ans;
    for(ll i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ans.push_back({i, 1});
            while((x /= i) % i == 0) ans.back().second++;
        }
    if(x != 1) ans.push_back({x, 1});
    return ans;
}
template <class T> vector<T> divisor(T x) {
    vector<T> ans;
    for(T i = 1; i * i <= x; i++)
        if(x % i == 0) {
            ans.pb(i);
            if(i * i != x) ans.pb(x / i);
        }
    return ans;
}
template <typename T> void zip(vector<T> &x) {
    vector<T> y = x;
    UNIQUE(y);
    for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); }
}
template <class S> void fold_in(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void fold_in(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto e : a) v.emplace_back(e);
    fold_in(v, tail...);
}
template <class S> void renumber(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void renumber(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto &&e : a) e = lb(v, e);
    renumber(v, tail...);
}
template <class S, class... Args> vector<S> zip(vector<S> &head, Args &&...args) {
    vector<S> v;
    fold_in(v, head, args...);
    sort(all(v)), v.erase(unique(all(v)), v.end());
    renumber(v, head, args...);
    return v;
}
template <typename T> vector<T> RUI(const vector<T> &v) {
    vector<T> res(v.size() + 1);
    for(int i = 0; i < v.size(); i++) res[i + 1] = res[i] + v[i];
    return res;
}
// 反時計周りに 90 度回転
template <typename T> void rot(vector<vector<T>> &v) {
    if(empty(v)) return;
    int n = v.size(), m = v[0].size();
    vector res(m, vector<T>(n));
    rep(i, n) rep(j, m) res[m - 1 - j][i] = v[i][j];
    v.swap(res);
}
// x in [l, r)
template <class T, class S> bool inc(const T &x, const S &l, const S &r) { return l <= x and x < r; }

// 便利関数
constexpr ll ten(int n) { return n == 0 ? 1 : ten(n - 1) * 10; }
constexpr ll tri(ll n) { return n * (n + 1) / 2; }
// l + ... + r
constexpr ll tri(ll l, ll r) { return (l + r) * (r - l + 1) / 2; }
ll max(int x, ll y) { return max((ll)x, y); }
ll max(ll x, int y) { return max(x, (ll)y); }
int min(int x, ll y) { return min((ll)x, y); }
int min(ll x, int y) { return min(x, (ll)y); }
// bit 演算系
ll pow2(int i) { return 1LL << i; }
int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(ll t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int lowbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int lowbit(ll a) { return a == 0 ? 64 : __builtin_ctzll(a); }
// int allbit(int n) { return (1 << n) - 1; }
constexpr ll mask(int n) { return (1LL << n) - 1; }
// int popcount(signed t) { return __builtin_popcount(t); }
// int popcount(ll t) { return __builtin_popcountll(t); }
int popcount(uint64_t t) { return __builtin_popcountll(t); }
static inline uint64_t popcount64(uint64_t x) {
    uint64_t m1 = 0x5555555555555555ll;
    uint64_t m2 = 0x3333333333333333ll;
    uint64_t m4 = 0x0F0F0F0F0F0F0F0Fll;
    uint64_t h01 = 0x0101010101010101ll;

    x -= (x >> 1) & m1;
    x = (x & m2) + ((x >> 2) & m2);
    x = (x + (x >> 4)) & m4;

    return (x * h01) >> 56;
}
bool ispow2(int i) { return i && (i & -i) == i; }

ll rnd(ll l, ll r) { //[l, r)
#ifdef noimi
    static mt19937_64 gen;
#else
    static mt19937_64 gen(chrono::steady_clock::now().time_since_epoch().count());
#endif
    return uniform_int_distribution<ll>(l, r - 1)(gen);
}
ll rnd(ll n) { return rnd(0, n); }

template <class t> void random_shuffle(vc<t> &a) { rep(i, si(a)) swap(a[i], a[rnd(0, i + 1)]); }

int in() {
    int x;
    cin >> x;
    return x;
}
ll lin() {
    unsigned long long x;
    cin >> x;
    return x;
}

template <class T, class S> pair<T, S> operator-(const pair<T, S> &x) { return pair<T, S>(-x.first, -x.second); }
template <class T, class S> pair<T, S> operator-(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi - y.fi, x.se - y.se); }
template <class T, class S> pair<T, S> operator+(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi + y.fi, x.se + y.se); }
template <class T> pair<T, T> operator&(const pair<T, T> &l, const pair<T, T> &r) { return pair<T, T>(max(l.fi, r.fi), min(l.se, r.se)); }
template <class T, class S> pair<T, S> operator+=(pair<T, S> &l, const pair<T, S> &r) { return l = l + r; }
template <class T, class S> pair<T, S> operator-=(pair<T, S> &l, const pair<T, S> &r) { return l = l - r; }
template <class T> bool intersect(const pair<T, T> &l, const pair<T, T> &r) { return (l.se < r.se ? r.fi < l.se : l.fi < r.se); }

template <typename T> struct edge {
    int from, to;
    T cost;
    int id;
    edge(int to, T cost) : from(-1), to(to), cost(cost) {}
    edge(int from, int to, T cost) : from(from), to(to), cost(cost) {}
    edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {}
    constexpr bool operator<(const edge<T> &rhs) const noexcept { return cost < rhs.cost; }
    edge &operator=(const int &x) {
        to = x;
        return *this;
    }
    operator int() const { return to; }
    friend ostream operator<<(ostream &os, edge &e) { return os << e.to; }
};
template <typename T> using Edges = vector<edge<T>>;

using Tree = vector<vector<int>>;
using Graph = vector<vector<int>>;
template <class T> using Wgraph = vector<vector<edge<T>>>;
Graph getG(int n, int m = -1, bool directed = false, int margin = 1) {
    Tree res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        cin >> a >> b;
        a -= margin, b -= margin;
        res[a].emplace_back(b);
        if(!directed) res[b].emplace_back(a);
    }
    return res;
}
Graph getTreeFromPar(int n, int margin = 1) {
    Graph res(n);
    for(int i = 1; i < n; i++) {
        int a;
        cin >> a;
        res[a - margin].emplace_back(i);
    }
    return res;
}
template <class T> Wgraph<T> getWg(int n, int m = -1, bool directed = false, int margin = 1) {
    Wgraph<T> res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        T c;
        scan(a), scan(b), scan(c);
        a -= margin, b -= margin;
        res[a].emplace_back(b, c);
        if(!directed) res[b].emplace_back(a, c);
    }
    return res;
}
void add(Graph &G, int x, int y) { G[x].eb(y), G[y].eb(x); }
template <class S, class T> void add(Wgraph<S> &G, int x, int y, T c) { G[x].eb(y, c), G[y].eb(x, c); }

#define TEST                                                                                                                                                   \
    INT(testcases);                                                                                                                                            \
    while(testcases--)

istream &operator>>(istream &is, i128 &v) {
    string s;
    is >> s;
    v = 0;
    for(int i = 0; i < (int)s.size(); i++) {
        if(isdigit(s[i])) { v = v * 10 + s[i] - '0'; }
    }
    if(s[0] == '-') { v *= -1; }
    return is;
}

ostream &operator<<(ostream &os, const i128 &v) {
    if(v == 0) { return (os << "0"); }
    i128 num = v;
    if(v < 0) {
        os << '-';
        num = -num;
    }
    string s;
    for(; num > 0; num /= 10) { s.push_back((char)(num % 10) + '0'); }
    reverse(s.begin(), s.end());
    return (os << s);
}
namespace aux {
template <typename T, unsigned N, unsigned L> struct tp {
    static void output(std::ostream &os, const T &v) {
        os << std::get<N>(v) << (&os == &cerr ? ", " : " ");
        tp<T, N + 1, L>::output(os, v);
    }
};
template <typename T, unsigned N> struct tp<T, N, N> {
    static void output(std::ostream &os, const T &v) { os << std::get<N>(v); }
};
} // namespace aux
template <typename... Ts> std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &t) {
    if(&os == &cerr) { os << '('; }
    aux::tp<std::tuple<Ts...>, 0, sizeof...(Ts) - 1>::output(os, t);
    if(&os == &cerr) { os << ')'; }
    return os;
}
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &p) {
    if(&os == &cerr) { return os << "(" << p.first << ", " << p.second << ")"; }
    return os << p.first << " " << p.second;
}
template <class Ch, class Tr, class Container> std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os, const Container &x) {
    bool f = true;
    if(&os == &cerr) os << "[";
    for(auto &y : x) {
        if(&os == &cerr)
            os << (f ? "" : ", ") << y;
        else
            os << (f ? "" : " ") << y;
        f = false;
    }
    if(&os == &cerr) os << "]";
    return os;
}

#ifdef noimi
#undef endl
void debug() { cerr << endl; }
void debug(bool) { cerr << endl; }
template <class Head, class... Tail> void debug(bool is_front, Head head, Tail... tail) {
    if(!is_front) cerr << ", ";
    cerr << head;
    debug(false, tail...);
}

#define dump(args...)                                                                                                                                          \
    {                                                                                                                                                          \
        vector<string> _debug = _split(#args, ',');                                                                                                            \
        err(true, begin(_debug), args);                                                                                                                        \
    }

vector<string> _split(const string &s, char c) {
    vector<string> v;
    stringstream ss(s);
    string x;
    while(getline(ss, x, c)) {
        if(empty(v))
            v.eb(x);
        else {
            bool flag = false;
            for(auto [c, d] : {pair('(', ')'), pair('[', ']'), pair('{', '}')}) {
                if(count(all(v.back()), c) != count(all(v.back()), d)) flag = true;
            }
            if(flag)
                v.back() += "," + x;
            else
                v.eb(x);
        }
    }
    return move(v);
}

void err(bool, vector<string>::iterator) { cerr << endl; }
template <typename T, typename... Args> void err(bool is_front, vector<string>::iterator it, T a, Args... args) {
    if(!is_front) cerr << ", ";
    cerr << it->substr((*it)[0] == ' ', (*it).size()) << " = " << a, err(false, ++it, args...);
}

// #define dump(...) cerr << #__VA_ARGS__ << " : ", debug(true, __VA_ARGS__)
#else
#define dump(...) static_cast<void>(0)
#define dbg(...) static_cast<void>(0)
#endif
void OUT() { cout << endl; }
template <class Head, class... Tail> void OUT(const Head &head, const Tail &...tail) {
    cout << head;
    if(sizeof...(tail)) cout << ' ';
    OUT(tail...);
}

template <typename T> static constexpr T inf = numeric_limits<T>::max() / 2;
template <class T, class S> constexpr pair<T, S> inf<pair<T, S>> = {inf<T>, inf<S>};

template <class F> struct REC {
    F f;
    REC(F &&f_) : f(std::forward<F>(f_)) {}
    template <class... Args> auto operator()(Args &&...args) const { return f(*this, std::forward<Args>(args)...); }
};

template <class S> vector<pair<S, int>> runLength(const vector<S> &v) {
    vector<pair<S, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}
vector<pair<char, int>> runLength(const string &v) {
    vector<pair<char, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}

int toint(const char &c, const char start = 'a') { return c - start; }
int toint(const char &c, const string &chars) { return find(all(chars), c) - begin(chars); }
int alphabets_to_int(const char &c) { return (islower(c) ? c - 'a' : c - 'A' + 26); }
template <typename T> auto toint(const T &v, const char &start = 'a') {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
template <typename T> auto toint(const T &v, const string &start) {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
// a -> 0, A -> 26
template <typename T> auto alphabets_to_int(const T &s) {
    vector<decltype(alphabets_to_int(s[0]))> res;
    res.reserve(s.size());
    for(auto &&e : s) { res.emplace_back(alphabets_to_int(e)); }
    return res;
}

template <class T, class F> T bin_search(T ok, T ng, const F &f) {
    while(abs(ok - ng) > 1) {
        T mid = ok + ng >> 1;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
template <class T, class F> T bin_search_double(T ok, T ng, const F &f, int iter = 80) {
    while(iter--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(11);
    }
} setup_io;

#pragma endregion

int a, b, C, M;
int r() {
    a = 36969 * (a & M) + (a >> 16);
    b = 18000 * (b & M) + (b >> 16);
    return (C & ((a << 16) + b)) % 1000000;
}

int main() {
    rep(1000) {
        INT(m, n, A, B);
        if(!n and !m) exit(0);
        if(m + n > 1000) dump(m, n, A, B);
        VEC3(int, x, y, z, m);
        { a = A, b = B, C = ~(1 << 31), M = (1 << 16) - 1; }

        rep(n) { x.eb(r()), y.eb(r()), z.eb(r()); }

        n += m;

        auto id = iota(n);
        sort(all(id), [&](int i, int j) { return z[i] != z[j] ? z[i] < z[j] : x[i] != x[j] ? x[i] > x[j] : y[i] > y[j]; });

        vector<set<pii>> dp;
        fore(i, id) {
            int k = bin_search(-1, si(dp), [&](int k) {
                auto it = dp[k].lower_bound(pii(x[i] - 1, y[i]));
                return it != begin(dp[k]) and prev(it)->se < y[i];
            });
            if(k + 1 < si(dp)) {
                auto &s = dp[k + 1];
                auto it = s.lower_bound(pii(x[i], y[i]));
                while(it != end(s) and it->se >= y[i]) { it = s.erase(it); }
                if(it != begin(s) and prev(it)->se <= y[i])
                    continue;
                else
                    s.emplace_hint(it, x[i], y[i]);
            } else {
                dp.eb(set<pii>());
                dp.back().emplace(x[i], y[i]);
            }
            // dump(dp);
        }

        OUT(si(dp));
    }
}
accuracy: 1
time_ms: 690
memory_kb: 14792
final_rank: 1

code_snippet: #pragma region Macros
#if defined(noimi) && defined(_GLIBCXX_DEBUG) && defined(_GLIBCXX_DEBUG_PEDANTIC)
// #pragma comment(linker, "/stack:200000000")
#include <stdc++.h>
#pragma GCC optimize("O3")
#else
#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #pragma GCC target("popcnt")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2,tune=native")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2")
// #pragma GCC target("avx2")
// #include <bits/stdc++.h>
#include <bits/stdc++.h>
#endif
#include <cstdint>
#include <immintrin.h>
#include <variant>

#ifdef noimi
#define oj_local(a, b) b
#else
#define oj_local(a, b) a
#endif

#define LOCAL if(oj_local(0, 1))
#define OJ if(oj_local(1, 0))

using namespace std;
using ll = long long;
using ull = unsigned long long int;
using i128 = __int128_t;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using ld = long double;
template <typename T> using vc = vector<T>;
template <typename T> using vvc = vector<vc<T>>;
template <typename T> using vvvc = vector<vvc<T>>;
using vi = vc<int>;
using vl = vc<ll>;
using vpi = vc<pii>;
using vpl = vc<pll>;
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
template <typename T> int si(const T &x) { return x.size(); }
template <class T, class S> inline bool chmax(T &a, const S &b) { return (a < b ? a = b, 1 : 0); }
template <class T, class S> inline bool chmin(T &a, const S &b) { return (a > b ? a = b, 1 : 0); }
vi iota(int n) {
    vi a(n);
    return iota(a.begin(), a.end(), 0), a;
}
template <typename T> vi iota(const vector<T> &a, bool greater = false) {
    vi res(a.size());
    iota(res.begin(), res.end(), 0);
    sort(res.begin(), res.end(), [&](int i, int j) {
        if(greater) return a[i] > a[j];
        return a[i] < a[j];
    });
    return res;
}

// macros
#define overload5(a, b, c, d, e, name, ...) name
#define overload4(a, b, c, d, name, ...) name
#define endl '\n'
#define REP0(n) for(ll jidlsjf = 0; jidlsjf < n; ++jidlsjf)
#define REP1(i, n) for(ll i = 0; i < (n); ++i)
#define REP2(i, a, b) for(ll i = (a); i < (b); ++i)
#define REP3(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep(...) overload4(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define per0(n) for(int jidlsjf = 0; jidlsjf < (n); ++jidlsjf)
#define per1(i, n) for(ll i = (n)-1; i >= 0; --i)
#define per2(i, a, b) for(ll i = (a)-1; i >= b; --i)
#define per3(i, a, b, c) for(ll i = (a)-1; i >= (b); i -= (c))
#define per(...) overload4(__VA_ARGS__, per3, per2, per1, per0)(__VA_ARGS__)
#define fore0(a) rep(a.size())
#define fore1(i, a) for(auto &&i : a)
#define fore2(a, b, v) for(auto &&[a, b] : v)
#define fore3(a, b, c, v) for(auto &&[a, b, c] : v)
#define fore4(a, b, c, d, v) for(auto &&[a, b, c, d] : v)
#define fore(...) overload5(__VA_ARGS__, fore4, fore3, fore2, fore1, fore0)(__VA_ARGS__)
#define fi first
#define se second
#define pb push_back
#define ppb pop_back
#define ppf pop_front
#define eb emplace_back
#define drop(s) cout << #s << endl, exit(0)
#define si(c) (int)(c).size()
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define rng(v, l, r) v.begin() + l, v.begin() + r
#define all(c) begin(c), end(c)
#define rall(c) rbegin(c), rend(c)
#define SORT(v) sort(all(v))
#define REV(v) reverse(all(v))
#define UNIQUE(x) SORT(x), x.erase(unique(all(x)), x.end())
template <typename T = ll, typename S> T SUM(const S &v) { return accumulate(all(v), T(0)); }
#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                                                         \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
constexpr pii dx4[4] = {pii{1, 0}, pii{0, 1}, pii{-1, 0}, pii{0, -1}};
constexpr pii dx8[8] = {{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};

namespace yesno_impl {
const string YESNO[2] = {"NO", "YES"};
const string YesNo[2] = {"No", "Yes"};
const string yesno[2] = {"no", "yes"};
const string firstsecond[2] = {"second", "first"};
const string FirstSecond[2] = {"Second", "First"};
const string possiblestr[2] = {"impossible", "possible"};
void YES(bool t = 1) { cout << YESNO[t] << endl; }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { cout << YesNo[t] << endl; }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { cout << yesno[t] << endl; }
void no(bool t = 1) { yes(!t); }
void first(bool t = 1) { cout << firstsecond[t] << endl; }
void First(bool t = 1) { cout << FirstSecond[t] << endl; }
void possible(bool t = 1) { cout << possiblestr[t] << endl; }
}; // namespace yesno_impl
using namespace yesno_impl;

#define INT(...)                                                                                                                                               \
    int __VA_ARGS__;                                                                                                                                           \
    IN(__VA_ARGS__)
#define LL(...)                                                                                                                                                \
    ll __VA_ARGS__;                                                                                                                                            \
    IN(__VA_ARGS__)
#define STR(...)                                                                                                                                               \
    string __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                                                                               \
    char __VA_ARGS__;                                                                                                                                          \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                                                                               \
    double __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define VEC(type, name, size)                                                                                                                                  \
    vector<type> name(size);                                                                                                                                   \
    IN(name)
#define VEC2(type, name1, name2, size)                                                                                                                         \
    vector<type> name1(size), name2(size);                                                                                                                     \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i])
#define VEC3(type, name1, name2, name3, size)                                                                                                                  \
    vector<type> name1(size), name2(size), name3(size);                                                                                                        \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i])
#define VEC4(type, name1, name2, name3, name4, size)                                                                                                           \
    vector<type> name1(size), name2(size), name3(size), name4(size);                                                                                           \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i], name4[i]);
#define VV(type, name, h, w)                                                                                                                                   \
    vector<vector<type>> name(h, vector<type>(w));                                                                                                             \
    IN(name)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &...tail) {
    scan(head);
    IN(tail...);
}

template <typename T, typename S> T ceil(T x, S y) {
    assert(y);
    return (y < 0 ? ceil(-x, -y) : (x > 0 ? (x + y - 1) / y : x / y));
}

template <typename T, typename S> T floor(T x, S y) {
    assert(y);
    return (y < 0 ? floor(-x, -y) : (x > 0 ? x / y : x / y - (x % y == 0 ? 0 : 1)));
}
template <class T> T POW(T x, int n) {
    T res = 1;
    for(; n; n >>= 1, x *= x)
        if(n & 1) res *= x;
    return res;
}
template <class T, class S> T POW(T x, S n, const ll &mod) {
    T res = 1;
    x %= mod;
    for(; n; n >>= 1, x = x * x % mod)
        if(n & 1) res = res * x % mod;
    return res;
}
vector<pll> factor(ll x) {
    vector<pll> ans;
    for(ll i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ans.push_back({i, 1});
            while((x /= i) % i == 0) ans.back().second++;
        }
    if(x != 1) ans.push_back({x, 1});
    return ans;
}
template <class T> vector<T> divisor(T x) {
    vector<T> ans;
    for(T i = 1; i * i <= x; i++)
        if(x % i == 0) {
            ans.pb(i);
            if(i * i != x) ans.pb(x / i);
        }
    return ans;
}
template <typename T> void zip(vector<T> &x) {
    vector<T> y = x;
    UNIQUE(y);
    for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); }
}
template <class S> void fold_in(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void fold_in(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto e : a) v.emplace_back(e);
    fold_in(v, tail...);
}
template <class S> void renumber(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void renumber(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto &&e : a) e = lb(v, e);
    renumber(v, tail...);
}
template <class S, class... Args> vector<S> zip(vector<S> &head, Args &&...args) {
    vector<S> v;
    fold_in(v, head, args...);
    sort(all(v)), v.erase(unique(all(v)), v.end());
    renumber(v, head, args...);
    return v;
}
template <typename T> vector<T> RUI(const vector<T> &v) {
    vector<T> res(v.size() + 1);
    for(int i = 0; i < v.size(); i++) res[i + 1] = res[i] + v[i];
    return res;
}
// 反時計周りに 90 度回転
template <typename T> void rot(vector<vector<T>> &v) {
    if(empty(v)) return;
    int n = v.size(), m = v[0].size();
    vector res(m, vector<T>(n));
    rep(i, n) rep(j, m) res[m - 1 - j][i] = v[i][j];
    v.swap(res);
}
// x in [l, r)
template <class T, class S> bool inc(const T &x, const S &l, const S &r) { return l <= x and x < r; }

// 便利関数
constexpr ll ten(int n) { return n == 0 ? 1 : ten(n - 1) * 10; }
constexpr ll tri(ll n) { return n * (n + 1) / 2; }
// l + ... + r
constexpr ll tri(ll l, ll r) { return (l + r) * (r - l + 1) / 2; }
ll max(int x, ll y) { return max((ll)x, y); }
ll max(ll x, int y) { return max(x, (ll)y); }
int min(int x, ll y) { return min((ll)x, y); }
int min(ll x, int y) { return min(x, (ll)y); }
// bit 演算系
ll pow2(int i) { return 1LL << i; }
int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(ll t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int lowbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int lowbit(ll a) { return a == 0 ? 64 : __builtin_ctzll(a); }
// int allbit(int n) { return (1 << n) - 1; }
constexpr ll mask(int n) { return (1LL << n) - 1; }
// int popcount(signed t) { return __builtin_popcount(t); }
// int popcount(ll t) { return __builtin_popcountll(t); }
int popcount(uint64_t t) { return __builtin_popcountll(t); }
static inline uint64_t popcount64(uint64_t x) {
    uint64_t m1 = 0x5555555555555555ll;
    uint64_t m2 = 0x3333333333333333ll;
    uint64_t m4 = 0x0F0F0F0F0F0F0F0Fll;
    uint64_t h01 = 0x0101010101010101ll;

    x -= (x >> 1) & m1;
    x = (x & m2) + ((x >> 2) & m2);
    x = (x + (x >> 4)) & m4;

    return (x * h01) >> 56;
}
bool ispow2(int i) { return i && (i & -i) == i; }

ll rnd(ll l, ll r) { //[l, r)
#ifdef noimi
    static mt19937_64 gen;
#else
    static mt19937_64 gen(chrono::steady_clock::now().time_since_epoch().count());
#endif
    return uniform_int_distribution<ll>(l, r - 1)(gen);
}
ll rnd(ll n) { return rnd(0, n); }

template <class t> void random_shuffle(vc<t> &a) { rep(i, si(a)) swap(a[i], a[rnd(0, i + 1)]); }

int in() {
    int x;
    cin >> x;
    return x;
}
ll lin() {
    unsigned long long x;
    cin >> x;
    return x;
}

template <class T, class S> pair<T, S> operator-(const pair<T, S> &x) { return pair<T, S>(-x.first, -x.second); }
template <class T, class S> pair<T, S> operator-(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi - y.fi, x.se - y.se); }
template <class T, class S> pair<T, S> operator+(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi + y.fi, x.se + y.se); }
template <class T> pair<T, T> operator&(const pair<T, T> &l, const pair<T, T> &r) { return pair<T, T>(max(l.fi, r.fi), min(l.se, r.se)); }
template <class T, class S> pair<T, S> operator+=(pair<T, S> &l, const pair<T, S> &r) { return l = l + r; }
template <class T, class S> pair<T, S> operator-=(pair<T, S> &l, const pair<T, S> &r) { return l = l - r; }
template <class T> bool intersect(const pair<T, T> &l, const pair<T, T> &r) { return (l.se < r.se ? r.fi < l.se : l.fi < r.se); }

template <typename T> struct edge {
    int from, to;
    T cost;
    int id;
    edge(int to, T cost) : from(-1), to(to), cost(cost) {}
    edge(int from, int to, T cost) : from(from), to(to), cost(cost) {}
    edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {}
    constexpr bool operator<(const edge<T> &rhs) const noexcept { return cost < rhs.cost; }
    edge &operator=(const int &x) {
        to = x;
        return *this;
    }
    operator int() const { return to; }
    friend ostream operator<<(ostream &os, edge &e) { return os << e.to; }
};
template <typename T> using Edges = vector<edge<T>>;

using Tree = vector<vector<int>>;
using Graph = vector<vector<int>>;
template <class T> using Wgraph = vector<vector<edge<T>>>;
Graph getG(int n, int m = -1, bool directed = false, int margin = 1) {
    Tree res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        cin >> a >> b;
        a -= margin, b -= margin;
        res[a].emplace_back(b);
        if(!directed) res[b].emplace_back(a);
    }
    return res;
}
Graph getTreeFromPar(int n, int margin = 1) {
    Graph res(n);
    for(int i = 1; i < n; i++) {
        int a;
        cin >> a;
        res[a - margin].emplace_back(i);
    }
    return res;
}
template <class T> Wgraph<T> getWg(int n, int m = -1, bool directed = false, int margin = 1) {
    Wgraph<T> res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        T c;
        scan(a), scan(b), scan(c);
        a -= margin, b -= margin;
        res[a].emplace_back(b, c);
        if(!directed) res[b].emplace_back(a, c);
    }
    return res;
}
void add(Graph &G, int x, int y) { G[x].eb(y), G[y].eb(x); }
template <class S, class T> void add(Wgraph<S> &G, int x, int y, T c) { G[x].eb(y, c), G[y].eb(x, c); }

#define TEST                                                                                                                                                   \
    INT(testcases);                                                                                                                                            \
    while(testcases--)

istream &operator>>(istream &is, i128 &v) {
    string s;
    is >> s;
    v = 0;
    for(int i = 0; i < (int)s.size(); i++) {
        if(isdigit(s[i])) { v = v * 10 + s[i] - '0'; }
    }
    if(s[0] == '-') { v *= -1; }
    return is;
}

ostream &operator<<(ostream &os, const i128 &v) {
    if(v == 0) { return (os << "0"); }
    i128 num = v;
    if(v < 0) {
        os << '-';
        num = -num;
    }
    string s;
    for(; num > 0; num /= 10) { s.push_back((char)(num % 10) + '0'); }
    reverse(s.begin(), s.end());
    return (os << s);
}
namespace aux {
template <typename T, unsigned N, unsigned L> struct tp {
    static void output(std::ostream &os, const T &v) {
        os << std::get<N>(v) << (&os == &cerr ? ", " : " ");
        tp<T, N + 1, L>::output(os, v);
    }
};
template <typename T, unsigned N> struct tp<T, N, N> {
    static void output(std::ostream &os, const T &v) { os << std::get<N>(v); }
};
} // namespace aux
template <typename... Ts> std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &t) {
    if(&os == &cerr) { os << '('; }
    aux::tp<std::tuple<Ts...>, 0, sizeof...(Ts) - 1>::output(os, t);
    if(&os == &cerr) { os << ')'; }
    return os;
}
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &p) {
    if(&os == &cerr) { return os << "(" << p.first << ", " << p.second << ")"; }
    return os << p.first << " " << p.second;
}
template <class Ch, class Tr, class Container> std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os, const Container &x) {
    bool f = true;
    if(&os == &cerr) os << "[";
    for(auto &y : x) {
        if(&os == &cerr)
            os << (f ? "" : ", ") << y;
        else
            os << (f ? "" : " ") << y;
        f = false;
    }
    if(&os == &cerr) os << "]";
    return os;
}

#ifdef noimi
#undef endl
void debug() { cerr << endl; }
void debug(bool) { cerr << endl; }
template <class Head, class... Tail> void debug(bool is_front, Head head, Tail... tail) {
    if(!is_front) cerr << ", ";
    cerr << head;
    debug(false, tail...);
}

#define dump(args...)                                                                                                                                          \
    {                                                                                                                                                          \
        vector<string> _debug = _split(#args, ',');                                                                                                            \
        err(true, begin(_debug), args);                                                                                                                        \
    }

vector<string> _split(const string &s, char c) {
    vector<string> v;
    stringstream ss(s);
    string x;
    while(getline(ss, x, c)) {
        if(empty(v))
            v.eb(x);
        else {
            bool flag = false;
            for(auto [c, d] : {pair('(', ')'), pair('[', ']'), pair('{', '}')}) {
                if(count(all(v.back()), c) != count(all(v.back()), d)) flag = true;
            }
            if(flag)
                v.back() += "," + x;
            else
                v.eb(x);
        }
    }
    return move(v);
}

void err(bool, vector<string>::iterator) { cerr << endl; }
template <typename T, typename... Args> void err(bool is_front, vector<string>::iterator it, T a, Args... args) {
    if(!is_front) cerr << ", ";
    cerr << it->substr((*it)[0] == ' ', (*it).size()) << " = " << a, err(false, ++it, args...);
}

// #define dump(...) cerr << #__VA_ARGS__ << " : ", debug(true, __VA_ARGS__)
#else
#define dump(...) static_cast<void>(0)
#define dbg(...) static_cast<void>(0)
#endif
void OUT() { cout << endl; }
template <class Head, class... Tail> void OUT(const Head &head, const Tail &...tail) {
    cout << head;
    if(sizeof...(tail)) cout << ' ';
    OUT(tail...);
}

template <typename T> static constexpr T inf = numeric_limits<T>::max() / 2;
template <class T, class S> constexpr pair<T, S> inf<pair<T, S>> = {inf<T>, inf<S>};

template <class F> struct REC {
    F f;
    REC(F &&f_) : f(std::forward<F>(f_)) {}
    template <class... Args> auto operator()(Args &&...args) const { return f(*this, std::forward<Args>(args)...); }
};

template <class S> vector<pair<S, int>> runLength(const vector<S> &v) {
    vector<pair<S, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}
vector<pair<char, int>> runLength(const string &v) {
    vector<pair<char, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}

int toint(const char &c, const char start = 'a') { return c - start; }
int toint(const char &c, const string &chars) { return find(all(chars), c) - begin(chars); }
int alphabets_to_int(const char &c) { return (islower(c) ? c - 'a' : c - 'A' + 26); }
template <typename T> auto toint(const T &v, const char &start = 'a') {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
template <typename T> auto toint(const T &v, const string &start) {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
// a -> 0, A -> 26
template <typename T> auto alphabets_to_int(const T &s) {
    vector<decltype(alphabets_to_int(s[0]))> res;
    res.reserve(s.size());
    for(auto &&e : s) { res.emplace_back(alphabets_to_int(e)); }
    return res;
}

template <class T, class F> T bin_search(T ok, T ng, const F &f) {
    while(abs(ok - ng) > 1) {
        T mid = ok + ng >> 1;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
template <class T, class F> T bin_search_double(T ok, T ng, const F &f, int iter = 80) {
    while(iter--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(11);
    }
} setup_io;

#pragma endregion

int a, b, C, M;
int r() {
    a = 36969 * (a & M) + (a >> 16);
    b = 18000 * (b & M) + (b >> 16);
    return (C & ((a << 16) + b)) % 1000000;
}

int main() {
    rep(1000) {
        INT(m, n, A, B);
        if(!n and !m) exit(0);
        if(m + n > 1000) dump(m, n, A, B);
        VEC3(int, x, y, z, m);
        { a = A, b = B, C = ~(1 << 31), M = (1 << 16) - 1; }

        rep(n) { x.eb(r()), y.eb(r()), z.eb(r()); }

        n += m;

        auto id = iota(n);
        sort(all(id), [&](int i, int j) { return z[i] != z[j] ? z[i] < z[j] : x[i] != x[j] ? x[i] > x[j] : y[i] > y[j]; });

        vector<set<pii>> dp;
        fore(i, id) {
            int k = bin_search(-1, si(dp), [&](int k) {
                auto it = dp[k].lower_bound(pii(x[i] - 1, y[i]));
                return it != begin(dp[k]) and prev(it)->se < y[i];
            });
            if(k + 1 < si(dp)) {
                auto &s = dp[k + 1];
                auto it = s.lower_bound(pii(x[i], y[i]));
                while(it != end(s) and it->se >= y[i]) { it = s.erase(it); }
                if(it != begin(s) and prev(it)->se <= y[i])
                    continue;
                else
                    s.emplace(x[i], y[i]);
            } else {
                dp.eb(set<pii>());
                dp.back().emplace(x[i], y[i]);
            }
            // dump(dp);
        }

        OUT(si(dp));
    }
}
accuracy: 1
time_ms: 730
memory_kb: 15076
final_rank: 3

code_snippet: #include <bits/stdc++.h>

#ifdef _MSC_VER
#  include <intrin.h>
#else
#  include <x86intrin.h>
#endif

#include <limits>
#include <type_traits>

namespace suisen {
// ! utility
template <typename ...Types>
using constraints_t = std::enable_if_t<std::conjunction_v<Types...>, std::nullptr_t>;
template <bool cond_v, typename Then, typename OrElse>
constexpr decltype(auto) constexpr_if(Then&& then, OrElse&& or_else) {
    if constexpr (cond_v) {
        return std::forward<Then>(then);
    } else {
        return std::forward<OrElse>(or_else);
    }
}

// ! function
template <typename ReturnType, typename Callable, typename ...Args>
using is_same_as_invoke_result = std::is_same<std::invoke_result_t<Callable, Args...>, ReturnType>;
template <typename F, typename T>
using is_uni_op = is_same_as_invoke_result<T, F, T>;
template <typename F, typename T>
using is_bin_op = is_same_as_invoke_result<T, F, T, T>;

template <typename Comparator, typename T>
using is_comparator = std::is_same<std::invoke_result_t<Comparator, T, T>, bool>;

// ! integral
template <typename T, typename = constraints_t<std::is_integral<T>>>
constexpr int bit_num = std::numeric_limits<std::make_unsigned_t<T>>::digits;
template <typename T, unsigned int n>
struct is_nbit { static constexpr bool value = bit_num<T> == n; };
template <typename T, unsigned int n>
static constexpr bool is_nbit_v = is_nbit<T, n>::value;

// ?
template <typename T>
struct safely_multipliable {};
template <>
struct safely_multipliable<int> { using type = long long; };
template <>
struct safely_multipliable<long long> { using type = __int128_t; };
template <>
struct safely_multipliable<unsigned int> { using type = unsigned long long; };
template <>
struct safely_multipliable<unsigned long int> { using type = __uint128_t; };
template <>
struct safely_multipliable<unsigned long long> { using type = __uint128_t; };
template <>
struct safely_multipliable<float> { using type = float; };
template <>
struct safely_multipliable<double> { using type = double; };
template <>
struct safely_multipliable<long double> { using type = long double; };
template <typename T>
using safely_multipliable_t = typename safely_multipliable<T>::type;

template <typename T, typename = void>
struct rec_value_type {
    using type = T;
};
template <typename T>
struct rec_value_type<T, std::void_t<typename T::value_type>> {
    using type = typename rec_value_type<typename T::value_type>::type;
};
template <typename T>
using rec_value_type_t = typename rec_value_type<T>::type;

} // namespace suisen

// ! type aliases
using i128 = __int128_t;
using u128 = __uint128_t;

template <typename T>
using pq_greater = std::priority_queue<T, std::vector<T>, std::greater<T>>;
template <typename T, typename U>
using umap = std::unordered_map<T, U>;

// ! macros (capital: internal macro)
#define OVERLOAD2(_1,_2,name,...) name
#define OVERLOAD3(_1,_2,_3,name,...) name
#define OVERLOAD4(_1,_2,_3,_4,name,...) name

#define REP4(i,l,r,s)  for(std::remove_reference_t<std::remove_const_t<decltype(r)>>i=(l);i<(r);i+=(s))
#define REP3(i,l,r)    REP4(i,l,r,1)
#define REP2(i,n)      REP3(i,0,n)
#define REPINF3(i,l,s) for(std::remove_reference_t<std::remove_const_t<decltype(l)>>i=(l);;i+=(s))
#define REPINF2(i,l)   REPINF3(i,l,1)
#define REPINF1(i)     REPINF2(i,0)
#define RREP4(i,l,r,s) for(std::remove_reference_t<std::remove_const_t<decltype(r)>>i=(l)+fld((r)-(l)-1,s)*(s);i>=(l);i-=(s))
#define RREP3(i,l,r)   RREP4(i,l,r,1)
#define RREP2(i,n)     RREP3(i,0,n)

#define rep(...)    OVERLOAD4(__VA_ARGS__, REP4   , REP3   , REP2   )(__VA_ARGS__)
#define rrep(...)   OVERLOAD4(__VA_ARGS__, RREP4  , RREP3  , RREP2  )(__VA_ARGS__)
#define repinf(...) OVERLOAD3(__VA_ARGS__, REPINF3, REPINF2, REPINF1)(__VA_ARGS__)

#define CAT_I(a, b) a##b
#define CAT(a, b) CAT_I(a, b)
#define UNIQVAR(tag) CAT(tag, __LINE__)
#define loop(n) for (std::remove_reference_t<std::remove_const_t<decltype(n)>> UNIQVAR(loop_variable) = n; UNIQVAR(loop_variable) --> 0;)

#define all(iterable) std::begin(iterable), std::end(iterable)
#define input(type, ...) type __VA_ARGS__; read(__VA_ARGS__)

#ifdef LOCAL
#  define debug(...) debug_internal(#__VA_ARGS__, __VA_ARGS__)

template <class T, class... Args>
void debug_internal(const char* s, T&& first, Args&&... args) {
    constexpr const char* prefix = "[\033[32mDEBUG\033[m] ";
    constexpr const char* open_brakets = sizeof...(args) == 0 ? "" : "(";
    constexpr const char* close_brakets = sizeof...(args) == 0 ? "" : ")";
    std::cerr << prefix << open_brakets << s << close_brakets << ": " << open_brakets << std::forward<T>(first);
    ((std::cerr << ", " << std::forward<Args>(args)), ...);
    std::cerr << close_brakets << "\n";
}

#else
#  define debug(...) void(0)
#endif

// ! I/O utilities

// __int128_t
std::ostream& operator<<(std::ostream& dest, __int128_t value) {
    std::ostream::sentry s(dest);
    if (s) {
        __uint128_t tmp = value < 0 ? -value : value;
        char buffer[128];
        char* d = std::end(buffer);
        do {
            --d;
            *d = "0123456789"[tmp % 10];
            tmp /= 10;
        } while (tmp != 0);
        if (value < 0) {
            --d;
            *d = '-';
        }
        int len = std::end(buffer) - d;
        if (dest.rdbuf()->sputn(d, len) != len) {
            dest.setstate(std::ios_base::badbit);
        }
    }
    return dest;
}
// __uint128_t
std::ostream& operator<<(std::ostream& dest, __uint128_t value) {
    std::ostream::sentry s(dest);
    if (s) {
        char buffer[128];
        char* d = std::end(buffer);
        do {
            --d;
            *d = "0123456789"[value % 10];
            value /= 10;
        } while (value != 0);
        int len = std::end(buffer) - d;
        if (dest.rdbuf()->sputn(d, len) != len) {
            dest.setstate(std::ios_base::badbit);
        }
    }
    return dest;
}

// pair
template <typename T, typename U>
std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& a) {
    return out << a.first << ' ' << a.second;
}
// tuple
template <unsigned int N = 0, typename ...Args>
std::ostream& operator<<(std::ostream& out, const std::tuple<Args...>& a) {
    if constexpr (N >= std::tuple_size_v<std::tuple<Args...>>) {
        return out;
    } else {
        out << std::get<N>(a);
        if constexpr (N + 1 < std::tuple_size_v<std::tuple<Args...>>) {
            out << ' ';
        }
        return operator<<<N + 1>(out, a);
    }
}
// vector
template <typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& a) {
    for (auto it = a.begin(); it != a.end();) {
        out << *it;
        if (++it != a.end()) out << ' ';
    }
    return out;
}
// array
template <typename T, size_t N>
std::ostream& operator<<(std::ostream& out, const std::array<T, N>& a) {
    for (auto it = a.begin(); it != a.end();) {
        out << *it;
        if (++it != a.end()) out << ' ';
    }
    return out;
}
inline void print() { std::cout << '\n'; }
template <typename Head, typename... Tail>
inline void print(const Head& head, const Tail &...tails) {
    std::cout << head;
    if (sizeof...(tails)) std::cout << ' ';
    print(tails...);
}
template <typename Iterable>
auto print_all(const Iterable& v, std::string sep = " ", std::string end = "\n") -> decltype(std::cout << *v.begin(), void()) {
    for (auto it = v.begin(); it != v.end();) {
        std::cout << *it;
        if (++it != v.end()) std::cout << sep;
    }
    std::cout << end;
}

__int128_t parse_i128(std::string& s) {
    __int128_t ret = 0;
    for (int i = 0; i < int(s.size()); i++) if ('0' <= s[i] and s[i] <= '9') ret = 10 * ret + s[i] - '0';
    if (s[0] == '-') ret = -ret;
    return ret;
}
__uint128_t parse_u128(std::string& s) {
    __uint128_t ret = 0;
    for (int i = 0; i < int(s.size()); i++) if ('0' <= s[i] and s[i] <= '9') ret = 10 * ret + s[i] - '0';
    return ret;
}
// __int128_t
std::istream& operator>>(std::istream& in, __int128_t& v) {
    std::string s;
    in >> s;
    v = parse_i128(s);
    return in;
}
// __uint128_t
std::istream& operator>>(std::istream& in, __uint128_t& v) {
    std::string s;
    in >> s;
    v = parse_u128(s);
    return in;
}
// pair
template <typename T, typename U>
std::istream& operator>>(std::istream& in, std::pair<T, U>& a) {
    return in >> a.first >> a.second;
}
// tuple
template <unsigned int N = 0, typename ...Args>
std::istream& operator>>(std::istream& in, std::tuple<Args...>& a) {
    if constexpr (N >= std::tuple_size_v<std::tuple<Args...>>) {
        return in;
    } else {
        return operator>><N + 1>(in >> std::get<N>(a), a);
    }
}
// vector
template <typename T>
std::istream& operator>>(std::istream& in, std::vector<T>& a) {
    for (auto it = a.begin(); it != a.end(); ++it) in >> *it;
    return in;
}
// array
template <typename T, size_t N>
std::istream& operator>>(std::istream& in, std::array<T, N>& a) {
    for (auto it = a.begin(); it != a.end(); ++it) in >> *it;
    return in;
}
template <typename ...Args>
void read(Args &...args) {
    (std::cin >> ... >> args);
}

// ! integral utilities

// Returns pow(-1, n)
template <typename T>
constexpr inline int pow_m1(T n) {
    return -(n & 1) | 1;
}
// Returns pow(-1, n)
template <>
constexpr inline int pow_m1<bool>(bool n) {
    return -int(n) | 1;
}

// Returns floor(x / y)
template <typename T>
constexpr inline T fld(const T x, const T y) {
    return (x ^ y) >= 0 ? x / y : (x - (y + pow_m1(y >= 0))) / y;
}
template <typename T>
constexpr inline T cld(const T x, const T y) {
    return (x ^ y) <= 0 ? x / y : (x + (y + pow_m1(y >= 0))) / y;
}

template <typename T, suisen::constraints_t<suisen::is_nbit<T, 16>> = nullptr>
__attribute__((target("popcnt"))) constexpr inline int popcount(const T x) { return _mm_popcnt_u32(x); }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 32>> = nullptr>
__attribute__((target("popcnt"))) constexpr inline int popcount(const T x) { return _mm_popcnt_u32(x); }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 64>> = nullptr>
__attribute__((target("popcnt"))) constexpr inline int popcount(const T x) { return _mm_popcnt_u64(x); }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 16>> = nullptr>
constexpr inline int count_lz(const T x) { return x ? __builtin_clz(x) : suisen::bit_num<T>; }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 32>> = nullptr>
constexpr inline int count_lz(const T x) { return x ? __builtin_clz(x) : suisen::bit_num<T>; }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 64>> = nullptr>
constexpr inline int count_lz(const T x) { return x ? __builtin_clzll(x) : suisen::bit_num<T>; }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 16>> = nullptr>
constexpr inline int count_tz(const T x) { return x ? __builtin_ctz(x) : suisen::bit_num<T>; }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 32>> = nullptr>
constexpr inline int count_tz(const T x) { return x ? __builtin_ctz(x) : suisen::bit_num<T>; }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 64>> = nullptr>
constexpr inline int count_tz(const T x) { return x ? __builtin_ctzll(x) : suisen::bit_num<T>; }
template <typename T>
constexpr inline int floor_log2(const T x) { return suisen::bit_num<T> -1 - count_lz(x); }
template <typename T>
constexpr inline int ceil_log2(const T x) { return floor_log2(x) + ((x & -x) != x); }
template <typename T>
constexpr inline int kth_bit(const T x, const unsigned int k) { return (x >> k) & 1; }
template <typename T>
constexpr inline int parity(const T x) { return popcount(x) & 1; }

// ! container

template <typename T, typename Comparator, suisen::constraints_t<suisen::is_comparator<Comparator, T>> = nullptr>
auto priqueue_comp(const Comparator comparator) {
    return std::priority_queue<T, std::vector<T>, Comparator>(comparator);
}

template <typename Iterable>
auto isize(const Iterable& iterable) -> decltype(int(iterable.size())) {
    return iterable.size();
}

template <typename T, typename Gen, suisen::constraints_t<suisen::is_same_as_invoke_result<T, Gen, int>> = nullptr>
auto generate_vector(int n, Gen generator) {
    std::vector<T> v(n);
    for (int i = 0; i < n; ++i) v[i] = generator(i);
    return v;
}
template <typename T>
auto generate_range_vector(T l, T r) {
    return generate_vector(r - l, [l](int i) { return l + i; });
}
template <typename T>
auto generate_range_vector(T n) {
    return generate_range_vector(0, n);
}

template <typename T>
void sort_unique_erase(std::vector<T>& a) {
    std::sort(a.begin(), a.end());
    a.erase(std::unique(a.begin(), a.end()), a.end());
}

template <typename InputIterator, typename BiConsumer>
auto foreach_adjacent_values(InputIterator first, InputIterator last, BiConsumer f) -> decltype(f(*first++, *last), void()) {
    if (first != last) for (auto itr = first, itl = itr++; itr != last; itl = itr++) f(*itl, *itr);
}
template <typename Container, typename BiConsumer>
auto foreach_adjacent_values(Container c, BiConsumer f) -> decltype(c.begin(), c.end(), void()) {
    foreach_adjacent_values(c.begin(), c.end(), f);
}

// ! other utilities

// x <- min(x, y). returns true iff `x` has chenged.
template <typename T>
inline bool chmin(T& x, const T& y) {
    if (y >= x) return false;
    x = y;
    return true;
}
// x <- max(x, y). returns true iff `x` has chenged.
template <typename T>
inline bool chmax(T& x, const T& y) {
    if (y <= x) return false;
    x = y;
    return true;
}

template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
std::string bin(T val, int bit_num = -1) {
    std::string res;
    if (bit_num >= 0) {
        for (int bit = bit_num; bit-- > 0;) res += '0' + ((val >> bit) & 1);
    } else {
        for (; val; val >>= 1) res += '0' + (val & 1);
        std::reverse(res.begin(), res.end());
    }
    return res;
}

template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
std::vector<T> digits_low_to_high(T val, T base = 10) {
    std::vector<T> res;
    for (; val; val /= base) res.push_back(val % base);
    if (res.empty()) res.push_back(T{ 0 });
    return res;
}
template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
std::vector<T> digits_high_to_low(T val, T base = 10) {
    auto res = digits_low_to_high(val, base);
    std::reverse(res.begin(), res.end());
    return res;
}

template <typename T>
std::string join(const std::vector<T>& v, const std::string& sep, const std::string& end) {
    std::ostringstream ss;
    for (auto it = v.begin(); it != v.end();) {
        ss << *it;
        if (++it != v.end()) ss << sep;
    }
    ss << end;
    return ss.str();
}

namespace suisen {}
using namespace suisen;
using namespace std;

struct io_setup {
    io_setup(int precision = 20) {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout << std::fixed << std::setprecision(precision);
    }
} io_setup_{};

// ! code from here

#include <algorithm>
#include <cassert>
#include <tuple>

#include <vector>
#include <map>
#include <unordered_map>

namespace suisen {
    template <typename T>
    struct FenwickTree {
        int n;
        vector<T> data;

        FenwickTree() : FenwickTree(0) {}
        FenwickTree(int n) : n(n), data(n, 0) {}
        int size() {
            return n;
        }
        void chmax(int i, T v) {
            for (++i; i <= n; i += (i & -i)) ::chmax(data[i - 1], v);
        }
        T max(int r) {
            T s = 0;
            for (; r; r -= r & -r) ::chmax(s, data[r - 1]);
            return s;
        }
    };
} // namespace suisen

namespace suisen {
    template <typename T>
    struct FenwickTree2DSparse {
        FenwickTree2DSparse() {}
        explicit FenwickTree2DSparse(int x_num) : n(x_num + 1), data(n), points(), pos_x(), pos_y(n) {}

        void add_point(int x, int y) {
            built = false;
            pos_x.push_back(x);
            points.emplace_back(x, y);
        }

        void build() {
            static constexpr int inf = std::numeric_limits<int>::max();
            built = true;
            pos_x.push_back(inf);
            std::sort(pos_x.begin(), pos_x.end());
            pos_x.erase(std::unique(pos_x.begin(), pos_x.end()), pos_x.end());
            assert(int(pos_x.size()) <= n);
            for (const auto& [x, y] : points) for (int k = comp_x(x) + 1; k <= n; k += k & -k) {
                pos_y[k - 1].push_back(y);
            }
            for (int k = 0; k < n; ++k) {
                pos_y[k].push_back(inf);
                std::sort(pos_y[k].begin(), pos_y[k].end());
                pos_y[k].erase(std::unique(pos_y[k].begin(), pos_y[k].end()), pos_y[k].end());
                data[k] = FenwickTree<T>(pos_y[k].size());
            }
        }

        void chmax(int x, int y, const T& val) {
            for (int k = comp_x(x) + 1; k <= n; k += k & -k) {
                data[k - 1].chmax(comp_y(k - 1, y), val);
            }
        }
        T max(int r, int u) {
            T res = 0;
            for (r = comp_x(r); r; r -= r & -r) ::chmax(res, data[r - 1].max(comp_y(r - 1, u)));
            return res;
        }

    private:
        int n, m;
        std::vector<FenwickTree<T>> data;
        std::vector<std::pair<int, int>> points;
        std::vector<int> pos_x;
        std::vector<std::vector<int>> pos_y;
        bool built = true;

        int comp_x(int x) const {
            return std::lower_bound(pos_x.begin(), pos_x.end(), x) - pos_x.begin();
        }
        int comp_y(int k, int y) const {
            return std::lower_bound(pos_y[k].begin(), pos_y[k].end(), y) - pos_y[k].begin();
        }
    };
} // namespace suisen

int main() {
    while (true) {
        input(int, m, n);
        input(int, A, B);
        if (m == 0 and n == 0 and A == 0 and B == 0) break;
        n += m;
        int C = ~(1 << 31), M = (1 << 16) - 1;
        auto r = [&]() -> int {
            A = 36969 * (A & M) + (A >> 16);
            B = 18000 * (B & M) + (B >> 16);
            return (C & ((A << 16) + B)) % 1000000;
        };

        vector<int> x(n), y(n), z(n);
        rep(i, n) {
            if (i < m) {
                read(x[i], y[i], z[i]);
            } else {
                x[i] = r();
                y[i] = r();
                z[i] = r();
            }
        }

        FenwickTree2DSparse<int> ft(n);
        rep(i, n) ft.add_point(y[i], z[i]);
        ft.build();

        vector<int> p(n);
        iota(all(p), 0);
        sort(all(p), [&](int i, int j) {
            if (x[i] != x[j]) return x[i] < x[j];
            if (y[i] != y[j]) return y[i] > y[j];
            return z[i] > z[j];
            }
        );

        for (int i : p) {
            ft.chmax(y[i], z[i], ft.max(y[i], z[i]) + 1);
        }

        print(ft.max(numeric_limits<int>::max(), numeric_limits<int>::max()));
    }

    return 0;
}
accuracy: 1
time_ms: 3940
memory_kb: 75080
final_rank: 15

code_snippet: #include <bits/stdc++.h>
// #define int long long
#define ff first
#define ss second
#define ll long long
#define ld long double
#define pb push_back
#define eb emplace_back
#define pii pair<int, int>
#define pll pair<ll, ll>
#define ti tuple<int, int, int>
#define vi vector<int>
#define vl vector<ll>
#define vii vector<pii>
#define sws ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define endl '\n'
#define teto(a, b) (((a)+(b)-1)/(b))
#define all(x) x.begin(), x.end()
#define forn(i, n) for(int i = 0; i < (int)n; i++)
#define forne(i, a, b) for(int i = a; i <= b; i++)
#define dbg(msg, var) cerr << msg << " " << var << endl;

#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")

using namespace std;

const int MAX = 2e5+10;
const ll MOD = 998244353;
const int INF = 0x3f3f3f3f;
const ll LLINF = 0x3f3f3f3f3f3f3f3f;
const ld EPS = 1e-10;
const ld PI = acos(-1);

// End Template //

int a, b, C = ~(1<<31), M = (1<<16)-1;
int r() {
    a = 36969 * (a & M) + (a >> 16);
    b = 18000 * (b & M) + (b >> 16);
    return (C & ((a << 16) + b)) % 1000000;
}

struct Segtree{
    vi t;
    int n;

    Segtree(int n){
        this->n = n;
        t.assign(2*n, 0);
    }

    int merge(int a, int b){
        return max(a, b);
    }

    void build(){
        for(int i=n-1;i>0;i--)
            t[i] = merge(t[i<<1], t[i<<1|1]);
    }

    int query(int l, int r){
        int resl = -INF, resr = -INF;
        for(l+=n, r+=n+1; l<r; l>>=1, r>>=1){
            if(l&1) resl = merge(resl, t[l++]);
            if(r&1) resr = merge(t[--r], resr);
        }
        return merge(resl, resr);
    }

    void update(int p, int value){
        p+=n;
        for(t[p]=max(t[p], value); p >>= 1;)
            t[p] = merge(t[p<<1], t[p<<1|1]);
    }
};

struct point{
    int x, y, z, id;
    bool left;
    point(int x=0, int y=0, int z=0): x(x), y(y), z(z){
        left = false;
    }
    bool operator<(point &o){
        if(x != o.x) return x < o.x;
        if(y != o.y) return y > o.y;
        return z < o.z;
    }
};


void cdq(int l, int r, vector<point> &a, vi &dp){
    if(l==r) return;

    int mid = (l+r) / 2;

    cdq(l, mid, a, dp);

    // compress z
    set<int> uz; map<int, int> idz;
    for(int i=l;i<=r;i++) uz.insert(a[i].z);
    int id = 0;
    for(auto z: uz) idz[z] = id++;

    vector<point> tmp;
    for(int i=l;i<=r;i++){
        tmp.pb(a[i]);
        tmp.back().x = 0;
        tmp.back().z = idz[tmp.back().z];
        if(i<=mid)
            tmp.back().left = true;
    }

    Segtree st(id);

    sort(tmp.rbegin(), tmp.rend());

    for(auto t: tmp){
        // cout << "tmp = " << t.x << " " << t.y << " " << t.z << " " << t.left << endl;
        if(t.left){
            st.update(t.z, dp[t.id]);
        }else{
            // cout << "ok\n";
            dp[t.id] = max(dp[t.id], st.query(0, t.z-1)+1);
        }
    }

    cdq(mid+1, r, a, dp);
}


int32_t main()
{sws;

    ll m, n;
    while(cin >> m >> n >> a >> b){
        if(m==0 and n==0 and a==0 and b==0) break;

        vector<point> vet(n+m);
        for(int i=0;i<m;i++){
            cin >> vet[i].x >> vet[i].y >> vet[i].z;
        }
        for(int i=m;i<n+m;i++){
            vet[i].x = r();
            vet[i].y = r();
            vet[i].z = r();
        }

        sort(vet.begin(), vet.end());

        for(int i=0;i<n+m;i++)
            vet[i].id = i;

        vi dp(n+m, 1);

        cdq(0, n+m-1, vet, dp);

        int ans = 0;
        for(int i=0;i<n+m;i++)
            ans = max(ans, dp[i]);


        // for(int i=0;i<n+m;i++)
        //     cout << dp[i] << " ";
        // cout << endl;

        cout << ans << endl;
        
    }

    return 0;
}

// overflow
// check border cases
// check limits (when initializing the answer too)
// check variables names, mod missing
// using set as multiset
// remember to permute the positions
// equal points/collinear points

// no ideas?
// try bb, dp
// invert the problem (calculate total - wrong)
// transform it in a graph somehow
// naive/brute
// when u find a dead end, read the statment again,
// to see if u understood the problem right.
accuracy: 1
time_ms: 7680
memory_kb: 82460
final_rank: 17

code_snippet: #include<bits/stdc++.h>

using namespace std;

#define _ ios_base::sync_with_stdio(0);cin.tie(0);
#define endl '\n'

typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;

typedef tuple<int, int, int> T;

const int MAX = 3e5 + 10;
const int MAX2 = 1e6 + 10;

int seg[2*MAX2];
int N = MAX2;

int query(int a, int b) {
	int ret = 0;
	for(a += N, b += N; a <= b; ++a /= 2, --b /= 2) {
		if (a % 2 == 1) ret = max(ret, seg[a]);
		if (b % 2 == 0) ret = max(ret, seg[b]);
	}
	return ret;
}

void update(int p, int x) {
	p += N;
	if (x == 0) seg[p] = 0;
	else seg[p] = max(seg[p], x);
	while (p /= 2) seg[p] = max(seg[2*p], seg[2*p+1]);
}

void lis2d(vector<vector<tuple<int, int, int>>>& v, vector<int>& dp, int l, int r) {
	if (l == r) {
		for (int i = 0; i < v[l].size(); i++) {
			int ii = get<2>(v[l][i]);
			dp[ii] = max(dp[ii], 1);
		}
		return;
	}
	
	int m = (l+r)/2;
	lis2d(v, dp, l, m);
	
	vector<tuple<int, int, int>> vv[2];
	for (int i = l; i <= r; i++) for (int j = 0; j < v[i].size(); j++)
		vv[i > m].push_back(v[i][j]);
	sort(vv[0].begin(), vv[0].end());
	sort(vv[1].begin(), vv[1].end());
	
	int mini = INF, i = 0;
	for (auto it : vv[1]) {
		int y, z, id;
		tie(y, z, id) = it;
		while (i < vv[0].size() and get<0>(vv[0][i]) < y) {
			int y2, z2, id2;
			tie(y2, z2, id2) = vv[0][i];
			mini = min(mini, z2);
			update(z2, dp[id2]);	
			i++;
		}
		int q = query(0, z-1);
		dp[id] = max(dp[id], q + 1);
	}

	for (i = 0; i < vv[0].size(); i++) {
		int y, z, id;
		tie(y, z, id) = vv[0][i];
		update(z, 0);
	}
	lis2d(v, dp, m+1, r);
}

vector<int> solve(vector<tuple<int, int, int>> v) {
	int n = v.size();
	vector<tuple<int, int, int, int>> vv;
	for (int i = 0; i < n; i++) {
		int x, y, z;
		tie(x, y, z) = v[i];
		vv.emplace_back(x, y, z, i);
	}
	sort(vv.begin(), vv.end());

	vector<vector<tuple<int, int, int>>> V;
	for (int i = 0; i < n; i++) {
		int j = i;
		V.emplace_back();
		while (j < n and get<0>(vv[j]) == get<0>(vv[i])) {
			int x, y, z, id;
			tie(x, y, z, id) = vv[j++];
			V.back().emplace_back(y, z, id);
		}
		i = j-1;
	}
	vector<int> dp(n);
	lis2d(V, dp, 0, V.size()-1);
	return dp;
}

int main() { _
	int m, n, A, B;
	while (cin >> m >> n >> A >> B) {
		if (n == 0 and m == 0 and A == 0 and B == 0) return 0;
		
		vector<tuple<int, int, int>> v;

		for (int i = 0; i < m; i++) {
			int x, y, z; cin >> x >> y >> z;
			v.emplace_back(x, y, z);
		}

		{
			int a = A, b = B, C = ~(1<<31), M = (1<<16)-1;
			for (int i = 0; i < n; i++) {
				vector<int> w;
				for (int j = 0; j < 3; j++) {
					a = 36969 * (a & M) + (a >> 16);
					b = 18000 * (b & M) + (b >> 16);
					w.push_back((C & ((a << 16) + b)) % 1000000);
				}		
				v.emplace_back(w[0], w[1], w[2]);
			}
		}

		auto dp = solve(v);

		int ans = 0;
		for (int i = 0; i < n+m; i++) ans = max(ans, dp[i]);
		cout << ans << endl;
	}
	exit(0);
}
accuracy: 1
time_ms: 3000
memory_kb: 51064
final_rank: 13

code_snippet: #include<bits/stdc++.h>

using namespace std;

#define _ ios_base::sync_with_stdio(0);cin.tie(0);
#define endl '\n'

typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;

typedef tuple<int, int, int> T;

const int MAX = 3e5 + 10;
const int MAX2 = 1e6 + 10;

vector<vector<T>> V;
int dp[MAX];

int seg[2*MAX2];
int N = MAX2;

int query(int a, int b) {
	int ret = 0;
	for(a += N, b += N; a <= b; ++a /= 2, --b /= 2) {
		if (a % 2 == 1) ret = max(ret, seg[a]);
		if (b % 2 == 0) ret = max(ret, seg[b]);
	}
	return ret;
}

void update(int p, int x) {
	p += N;
	if (x == 0) seg[p] = 0;
	else seg[p] = max(seg[p], x);
	while (p /= 2) seg[p] = max(seg[2*p], seg[2*p+1]);
}

void lis2d(int l, int r) {
	if (l == r) {
		for (int i = 0; i<V[l].size(); i++) {
			int ii = get<2>(V[l][i]);
			dp[ii] = max(dp[ii], 1);
		}
		return;
	}
	
	int m = (l+r)/2;
	lis2d(l, m);
	
	vector<T> v1, v2;
	for (int i = l; i <= r; i++) for (int j = 0; j < V[i].size(); j++) { 
		if (i <= m) v1.push_back(V[i][j]);
		else v2.push_back(V[i][j]);
	}
	sort(v1.begin(), v1.end());
	sort(v2.begin(), v2.end());
	
	int mini = INF;

	int i = 0;
	for (auto it : v2) {
		int y, z, id;
		tie(y, z, id) = it;
		while (i < v1.size() and get<0>(v1[i]) < y) {
			int y2, z2, id2;
			tie(y2, z2, id2) = v1[i];
			mini = min(mini, z2);
			update(z2, dp[id2]);	
			i++;
		}
		int q = query(0, z-1);
		dp[id] = max(dp[id], q + 1);
	}

	for (i = 0; i<v1.size(); i++) {
		int y, z, id;
		tie(y, z, id) = v1[i];
		update(z, 0);
	}
	lis2d(m+1, r);
}

int main() { _
	int m, n, A, B;
	while (cin >> m >> n >> A >> B) {
		if (n == 0 and m == 0 and A == 0 and B == 0) return 0;
		
		for (int i = 0; i<n+m; i++) dp[i] = 0;
		V.clear();
		vector<T> v;

		for (int i = 0; i<m; i++) {
			int x, y, z; cin >> x >> y >> z;
			v.emplace_back(x, y, z);
		}

		{
			int a = A, b = B, C = ~(1<<31), M = (1<<16)-1;
			for (int i = 0; i<n; i++) {
				vector<int> w;
				for (int j = 0; j<3; j++) {
					a = 36969 * (a & M) + (a >> 16);
					b = 18000 * (b & M) + (b >> 16);
					w.push_back((C & ((a << 16) + b)) % 1000000);
				}		
				v.emplace_back(w[0], w[1], w[2]);
			}
		}

		sort(v.begin(), v.end());

		for (int i = 0; i < n+m; i++) {
			int j = i;
			V.emplace_back();
			while (j < n+m and get<0>(v[j]) == get<0>(v[i])) {
				V.back().emplace_back(get<1>(v[j]), get<2>(v[j]), j);
				j++;
			}
			i = j-1;
		}
	
		lis2d(0, V.size()-1);
		int ans = 0;
		for (int i = 0; i<n+m; i++) ans = max(ans, dp[i]);
		cout << ans << endl;
	}
	exit(0);
}
accuracy: 1
time_ms: 2890
memory_kb: 40876
final_rank: 10

code_snippet: #include<bits/stdc++.h>
using namespace::std;

// Currently: WA :v

const int C = ~(1 << 31);
const int M = (1 << 16) - 1;
const int N = 300000 + 5;

int n;
int m;
int a;
int b;
int A;
int B;
int len;
int memo[N];
set<pair<int, int>> ft[N];

int r(){
	a = 36969 * (a & M) + (a >> 16);
	b = 18000 * (b & M) + (b >> 16);
	return (C & ((a << 16) + b)) % 1000000;
}

void compress(vector<int> &v){
	vector<int> values(v.begin(), v.end());
	sort(values.begin(), values.end());
	values.erase(unique(values.begin(), values.end()), values.end());
	for(int i = 0; i < v.size(); i++){
		v[i] = lower_bound(values.begin(), values.end(), v[i]) - values.begin();
	}
}

int get(int at, int val){
	if(ft[at].empty() or (*ft[at].begin()).first > val) return 0;
	set<pair<int, int>>::iterator it = ft[at].lower_bound(make_pair(val, -1));
	if(it == ft[at].end() or (*it).first > val) it--;
	return (*it).second;
}
	
int query(int y, int z){
	y++; z++;
	int res = 0;
	for(int j = y; j > 0; j &= j - 1){
		res = max(res, get(j, z));
	}
	return res;
}

void insert(int at, int pos, int val){
	if(ft[at].empty()){
		ft[at].emplace(make_pair(pos, val));
		return;
	}
	set<pair<int, int>>::iterator it = ft[at].lower_bound(make_pair(pos, -1));

	if(it != ft[at].end() and (*it).first == pos and (*it).second >= val) return;
	set<pair<int, int>>::iterator leq = it;
	if(leq != ft[at].begin()) leq--;
	if((*leq).first < pos and (*leq).second >= val) return;
	vector<pair<int, int>> to_remove;
	while(it != ft[at].end() and (*it).second <= val){
		to_remove.emplace_back(*it);
		it++;
	}
	for(auto e : to_remove) ft[at].erase(e);
	ft[at].emplace(make_pair(pos, val));
}

void update(int y, int z, int val){
	y++; z++;
	for(int j = y; j <= len; j += (-j) & j){
		insert(j, z, val);
	}
}

int solve(vector<int> &x, vector<int> &y, vector<int> &z){
	vector<int> p(len);
	iota(p.begin(), p.end(), 0);
	sort(p.begin(), p.end(), [&] (int i, int j){
		if(x[i] != x[j]) return x[i] < x[j];
		if(y[i] != y[j]) return y[i] < y[j];
		if(z[i] != z[j]) return z[i] < z[j];
		return false;
	});
	int ans = 0;
	int l = 0, r = 0;
	while(l < len){
		while(r < len and x[p[l]] == x[p[r]]) r++;
		for(int i = l; i < r; i++){
			int at = p[i];
			memo[i] = 1 + query(y[at] - 1, z[at] - 1);
			if(ans < memo[i]) ans = memo[i];
		}
		for(int i = l; i < r; i++){
			int at = p[i];
			update(y[at], z[at], memo[i]);
		}
		l = r;
	}
	return ans;
}

void clear(){
	for(int i = 0; i <= len; i++){
		ft[i].clear();
	}
}

int main(){
	while(scanf("%d %d %d %d", &m, &n, &a, &b) == 4 and m + n){
		len = n + m;
		vector<int> x(len), y(len), z(len);
		for(int i = 0; i < m; i++){
			scanf("%d %d %d", &x[i], &y[i], &z[i]);
		}
		for(int i = m; i < len; i++){
			x[i] = r();
			y[i] = r();
			z[i] = r();
		}
		compress(x); compress(y); compress(z);
		printf("%d\n", solve(x, y, z));
		clear();
	}
	return 0;
}
accuracy: 1
time_ms: 3730
memory_kb: 66916
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=1005,INF=1<<29;

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int N,nn,A,B;cin>>N>>nn>>A>>B;
        if(N+nn==0) break;
        vector<vector<int>> S(N);
        for(int i=0;i<N;i++){
            S[i].resize(3);
            for(int j=0;j<3;j++) cin>>S[i][j];
        }
        int a = A, b = B, C = ~(1<<31), M = (1<<16)-1;
        for(int i=0;i<nn;i++){
            S.push_back({});
            for(int j=0;j<3;j++){
                a = 36969 * (a & M) + (a >> 16);
                b = 18000 * (b & M) + (b >> 16);
                S.back().push_back((C & ((a << 16) + b)) % 1000000);
            }
        }
        
        sort(all(S),[](auto a,auto b){
            if(a[0]==b[0]){
                if(a[1]==b[1]) return a[2]>b[2];
                else return a[1]>b[1];
            }else{
                return a[0]<b[0];
            }
        });
        
        N=si(S);
        vector<set<pair<int,int>>> SE(N+1);
        for(int i=0;i<=N;i++){
            if(i) SE[i].insert(mp(-INF,INF));
            else SE[i].insert(mp(-INF,-INF+1));
            SE[i].insert(mp(INF,-INF));
        }
        for(int i=0;i<N;i++){
            int left=0,right=i+1;
            pair<int,int> x=mp(S[i][1],S[i][2]);
            while(right-left>1){
                int mid=(left+right)/2;
                auto it=SE[mid].lower_bound(mp(x.fi,-INF));
                it--;
                if((*it).se<x.se) left=mid;
                else right=mid;
            }
            int mid=right;
            auto it=SE[mid].lower_bound(x);
            it--;
            bool f=((*it).se>x.se);
            it++;
            while(it!=SE[mid].end()){
                if((*it).se>=x.se){
                    it=SE[mid].erase(it);
                }else{
                    break;
                }
            }
            if(f) SE[mid].insert(x);
        }
        
        int ans=-1;
        for(int i=0;i<=N;i++){
            for(auto a:SE[i]){
                if(abs(a.fi)<INF) ans=i;
            }
        }
        cout<<ans<<"\n";
    }
}
accuracy: 1
time_ms: 1940
memory_kb: 67864
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0; i<(int)(n); i++)

using ll = long long;

int a,b;
// const int C = ~(1<<31);
const int C = (1<<30) + ((1<<30) - 1);
const int M = (1<<16)-1;
int r() {
	a = 36969 * (a & M) + (a >> 16);
	b = 18000 * (b & M) + (b >> 16);
	return (C & ((a << 16) + b)) % 1000000;
}

using pii = pair<int,int>;

pair<int,pii> points[325252];

int main(){
	while(true){
		int n,m;
		scanf("%d%d%d%d",&n,&m,&a,&b);
		if(n+m+a+b==0)break;
		REP(i,n){
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			x++; y++; z++;
			points[i] = make_pair(x,pii(y,z));
		}
		REP(i,m){
			int x = r();
			int y = r();
			int z = r();
			x++; y++; z++;
			points[i+n] = make_pair(x,pii(y,z));
		}
		n += m;
		sort(points, points+n, [&](pair<int,pii> a, pair<int,pii> b){
			if(a.first != b.first)return a.first < b.first;
			return a.second > b.second;
		});
		const int N = 1000025;
		std::unordered_map<int,std::map<int,int>> bit;
		auto add = [&](int y, int z, int v){
			for(; y<N; y+=y&-y){
				// add to y
				if(bit.count(y)==0){
					bit[y] = std::map<int,int>();
					bit[y][-1] = -252521;
				}
				std::map<int,int> &mp = bit[y];
				auto it = mp.upper_bound(z); it--;
				if(it->second >= v)continue;
				mp[z] = v;
				it = mp.upper_bound(z);
				while(it != mp.end() && it->second <= v){
					mp.erase(it++);
				}
			}
		};
		auto query = [&](int y, int z){
			int ans = 0;
			for(; y>0; y-=y&-y){
				// get from y
				if(bit.count(y)==0)continue;
				std::map<int,int> &mp = bit[y];
				auto it = mp.upper_bound(z); it--;
				ans = max(ans, it->second);
			}
			return ans;
		};
		int ans = 0;
		REP(i,n){
			int x = points[i].first;
			int y = points[i].second.first;
			int z = points[i].second.second;
			int v = query(y-1, z-1) + 1;
			ans = max(ans, v);
			add(y,z,v);
		}
		printf("%d\n",ans);
	}
	return 0;
}
accuracy: 1
time_ms: 7480
memory_kb: 110408
final_rank: 18

code_snippet: #include <iostream>
#include <vector>
#include <cmath>
#include <string>
#include <climits>
#include <iomanip>
#include <algorithm>
#include <queue>
#include <map>
#include <tuple>
#include <iostream>
#include <deque>
#include <array>
#include <set>
#include <functional>
#include <memory>
#include <stack>

struct Point3 {
	int x, y, z;
};
struct Point2 {
	int x, y;
	bool operator<(const Point2 other) const { return x < other.x; }
};
class NonChainablePoints {
	std::set<Point2> set;
public:
	NonChainablePoints() {};
	bool can_chain(const Point2& point) const {
		auto hint = set.lower_bound(point);
		return hint != set.begin() && (--hint)->y < point.y;
	}
	void insert(const Point2& point) {
		auto hint = set.lower_bound(point);
		if (hint == set.end() || hint->x != point.x || hint->y >= point.y) {
			while (hint != set.end() && hint->y >= point.y) hint = set.erase(hint);
			set.insert(point);
		}
	}
	bool is_empty() const { return set.empty(); }
	bool is_not_empty() const { return !is_empty(); }
};
int r(int& a, int& b) {
	constexpr int C = ~(1 << 31);
	constexpr int M = (1 << 16) - 1;
	a = 36969 * (a & M) + (a >> 16);
	b = 18000 * (b & M) + (b >> 16);
	return (C & ((a << 16) + b)) % 1000000;
}
void append_points(std::vector<Point3>& points, int a, int b, const int n) {
	for (auto i = 0; i < n; ++i) {
		Point3 p;
		p.x = r(a, b);
		p.y = r(a, b);
		p.z = r(a, b);
		points.push_back(p);
	}
}
int solve(const int m, const int n, const int a, const int b) {
	std::vector<Point3> points(m);
	for (auto& p : points) std::cin >> p.x >> p.y >> p.z;
	append_points(points, a, b, n);
	std::sort(points.begin(), points.end(), [](const Point3& a, const Point3& b) {return (a.z == b.z) ? a.x > b.x : a.z < b.z; });
	std::vector<NonChainablePoints> sets(m + n);
	for (const auto point : points) {
		const Point2 p{ point.x, point.y };
		auto left = 0;
		auto right = sets.size();
		while (left < right) {
			auto mid = (left + right) / 2;
			if (sets[mid].can_chain(p)) left = mid + 1;
			else right = mid;
		}
		sets[right].insert(p);
	}
	for (auto i = 0; i < sets.size(); ++i) {
		if (sets[i].is_empty()) return i;
	}
	return sets.size();
}
int main() {
	std::vector<int>result;
	while (true) {
		int m, n, a, b;
		std::cin >> m >> n >> a >> b;
		if (m == 0 && n == 0) break;
		result.push_back(solve(m, n, a, b));
	}
	for (const auto r : result) std::cout << r << '\n';
}
accuracy: 1
time_ms: 960
memory_kb: 26876
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;

int a, b;
constexpr int C = ~(1 << 31);
constexpr int M = (1 << 16) - 1;

int r() {
    a = 36969 * (a & M) + (a >> 16);
    b = 18000 * (b & M) + (b >> 16);
    return (C & ((a << 16) + b)) % 1000000;
}

struct point {
    int y, z;

    point(int y_, int z_) : y(y_), z(z_) {}
    bool operator<(point const& p) const {
        return y < p.y;
    }
};

int main() {
    ios_base::sync_with_stdio(false); cin.tie(0);

    int m, n;
    while(cin >> m >> n >> a >> b, n + m) {
        vector<tuple<int, int, int>> ps(n + m);
        for(int i = 0; i < m; ++i) {
            int x, y, z; cin >> x >> y >> z;
            ps[i] = make_tuple(x, -y, -z);
        }
        for(int i = m; i < n + m; ++i) {
            const int x = r(), y = r(), z = r();
            ps[i] = make_tuple(x, -y, -z);
        }
        sort(begin(ps), end(ps));
        vector<point> ps2;
        for(int i = 0; i < n + m; ++i) {
            ps2.emplace_back(-get<1>(ps[i]), -get<2>(ps[i]));
        }

        int ans = 0;
        vector<set<point>> dp(n + m + 1);
        dp[0].emplace(0, 0);
        for(auto const& p : ps2) {
            auto check = [&] (int i) {
                auto it = dp[i].lower_bound(p);
                if(it == dp[i].begin()) return false;
                it = prev(it);
                return p.y > it->y && p.z > it->z;
            };
            int lb = 0, ub = n + m;
            while(ub - lb > 1) {
                const int mid = (ub + lb) >> 1;
                (check(mid) ? lb : ub) = mid;
            }
            auto it = dp[ub].lower_bound(p);
            while(it != dp[ub].end() && it->z >= p.z) {
                it = dp[ub].erase(it);
            }
            if(it == dp[ub].begin() || prev(it)->z > p.z) {
                dp[ub].insert(p);
            }
            ans = max(ans, ub);
        }

        cout << ans << endl;
    }
}
accuracy: 1
time_ms: 750
memory_kb: 27212
final_rank: 6