Problem:
Problem G: Longest Chain

Let us compare two triples a = (xa, ya, za) and b = (xb, yb, zb) by a partial order ∠ defined as follows.

a ∠ b ⇔ xa < xb and ya < yb and za < zb

Your mission is to find, in the given set of triples, the longest ascending series a1 ∠ a2 ∠ ... ∠ ak.

Input

The input is a sequence of datasets, each specifying a set of triples formatted as follows.

m n A B
x1 y1 z1
x2 y2 z2
...
xm ym zm

Here, m, n, A and B in the first line, and all of xi, yi and zi (i = 1, . . . , m) in the following lines are non-negative integers.

Each dataset specifies a set of m + n triples. The triples p1 through pm are explicitly specified in the dataset, the i-th triple pi being (xi, yi, zi). 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 3n calls of r() defined as above yield values of xm+1, ym+1, zm+1, xm+2, ym+2, zm+2, ..., xm+n, ym+n, and zm+n, in this order.

You can assume that 1 ≤ m + n ≤ 3 × 105, 1 ≤ A,B ≤ 216, and 0 ≤ xk, yk, zk < 106 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 × 106.

Output

For each dataset, output the length of the longest ascending series of triples in the specified set. If pi1 ∠ pi2 ∠ ... ∠ pik 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

Solution in C++ (judge verdict: Memory Limit Exceeded)

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
#include<utility>
#include<cstdlib>
using namespace std;



namespace _RMQ{

const int nil=0;
int func(int a,int b){
	return max(a,b);
}


class SparseSegtree{
	struct Node{
		char height;
		pair<int,int>  key;
		int value, rangev;

		Node *left,*right;
		Node(pair<int,int> k,int v)
			:height(1),key(k),value(v),rangev(v),left(0),right(0){}
		~Node(){
			if(left)delete left;
			if(right)delete right;
		}
		Node *rotate_right(){
			Node *s=left;
			left=s->right;
			s->right=this;
			return s;
		}
		Node *rotate_left(){
			Node *s=right;
			right=s->left;
			s->left=this;
			return s;
		}

		int query(int a,int b,int l,int r)const{
			if(!this||r<=a||b<=l)return nil;
			if(a<=l&&r<=b)return rangev;
			int res=func(left->query(a,b,l,key.first+1),right->query(a,b,key.first,r));
			if(a<=key.first&&key.first<b)res=func(res,value);
			return res;
		}
		Node *insert(pair<int,int> k,int v){
			if(!this)return new Node(k,v);
			if(k < key){
				left = left->insert(k,v);
			}else{
				right = right->insert(k,v);
			}
			return balance();
		}
		Node *erase(pair<int,int> k){
			if(!this)return NULL;
			if(k==key){
				Node *le=left,*ri=right;
				left=right=NULL;
				delete this;
				if(!le)return ri;
				if(!ri)return le;
				Node *t;
				le = le->erase_max(&t);
				t->left = le;
				t->right = ri;
				return t->balance();
			}
			if(k < key){
				left = left->erase(k);
			}else if(key < k){
				right = right->erase(k);
			}else return this;
			return balance();
		}

		Node *balance(){
			int bf = (right?right->height:0)-(left?left->height:0);
			if(2==bf){
				Node *t=right;
				if((t->right?t->right->height:0) < (t->left?t->left->height:0)){
					right = t->rotate_right();
				}
				return rotate_left()->update();
			}else if(bf==-2){
				Node *t=left;
				if((t->right?t->right->height:0) > (t->left?t->left->height:0)){
					left = t->rotate_left();
				}
				return rotate_right()->update();
			}
			updates();
			return this;
		}
		Node *update(){
			if(left)left->updates();
			if(right)right->updates();
			updates();
			return this;
		}
		void updates(){
			update_height();
			update_value();
		}
		void update_value(){
			rangev=value;
			if(left)rangev=func(rangev,left->rangev);
			if(right)rangev=func(rangev,right->rangev);
		}
		void update_height(){
			if(!this)return;
			if(right){
				if(left && right->height < left->height)height=left->height+1;
				else height=right->height+1;
			}else if(left)height=left->height+1;
			else height=1;
		}
		Node* erase_max(Node **maxnode){
			if(right){
				right = right->erase_max(maxnode);
				return balance();
			}else{
				*maxnode=this;
				return left;
			}
		}
	} *root;

	int calc_max_key()const{
		Node *p=root;
		if(!p)return -1;
		while(p->right)p=p->right;
		return p->key.first;
	}
	int max_key;
public:
	SparseSegtree():root(0),max_key(-1){}
	~SparseSegtree(){if(root)delete root;}
	void insert(pair<int,int> k,int v){
		max_key=max(max_key,k.first);
		root=root->insert(k,v);
	}
	void erase(pair<int,int> k){
		root=root->erase(k);
		if(k.first==max_key)max_key=calc_max_key();
	}
	int query(int a,int b)const{//[a,b)
		return root->query(a,b,0,max_key+1);
	}
	bool empty()const{
		return root;
	}
	int height()const{
		return root?root->height:0;
	}
};

};


template<int XSIZE=1<<20>
class Dynamic2DRMQ{
	struct Node{
		_RMQ::SparseSegtree rmq;
		Node *left,*right;
		Node():left(0),right(0){}
		~Node(){
			delete left;
			delete right;
		}
		int query(int a,int b,int l,int r,int ys,int ye)const{
			if(!this||r<=a||b<=l)return _RMQ::nil;
			if(a<=l&&r<=b)return rmq.query(ys,ye);
			return _RMQ::func(left->query(a,b,l,(l+r)/2,ys,ye),right->query(a,b,(l+r)/2,r,ys,ye));
		}
		void insert(int x,int y,int v,int l,int r){
			rmq.insert(make_pair(y,x),v);
			if(r-l==1)return;
			if(x<(l+r)/2){
				if(!left)left=new Node();
				left->insert(x,y,v,l,(l+r)/2);
			}else{
				if(!right)right=new Node();
				right->insert(x,y,v,(l+r)/2,r);
			}
		}
		void erase(int x,int y,int l,int r){
			rmq.erase(make_pair(y,x));
			if(r-l==1)return;
			if(x<(l+r)/2){
				left->erase(x,y,l,(l+r)/2);
				if(left->rmq.empty()){
					delete left;
					left=0;
				}
			}else{
				right->erase(x,y,(l+r)/2,r);
				if(right->empty()){
					delete right;
					right=0;
				}
			}
		}
	};
	Node *root;
public:
	Dynamic2DRMQ():root(new Node()){}
	~Dynamic2DRMQ(){delete root;}
	void insert(int x,int y,int v){
		root->insert(x,y,v,0,XSIZE);
	}
	void erase(int x,int y){
		root->erase(x,y,0,XSIZE);
	}
	int query(int xs,int xe,int ys,int ye){//[xs,xe)*[ys,ye)
		return root->query(xs,xe,0,XSIZE,ys,ye);
	}
};



int m,n,A,B;

int r() {
	static const 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;
}


int main(){
	while(cin>>m>>n>>A>>B,m|n){
		vector<pair<int,pair<int,int> > > v(n+m),w;
		for(int i=0;i<m;i++){
			cin>>v[i].first>>v[i].second.first>>v[i].second.second;
		}
		for(int i=m;i<m+n;i++){
			v[i].first=r();
			v[i].second.first=r();
			v[i].second.second=r();
		}
		sort(v.begin(),v.end());
		int ans=0;
		Dynamic2DRMQ<> rmq2d;
		int prevx=-1;
		for(int i=0;i<m+n;i++){
			if(prevx<v[i].first){
				for(int j=0;j<w.size();j++)
					rmq2d.insert(w[j].second.first,w[j].second.second, w[j].first);
				w.clear();
				prevx=v[i].first;
			}
			int t=rmq2d.query(0,v[i].second.first,0,v[i].second.second)+1;
			ans=max(ans,t);
			w.push_back(make_pair(t,make_pair(v[i].second.first,v[i].second.second) ) );
		}

		cout<<ans<<endl;
	}
	return 0;
}