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

const int N = 200010;
const int LOGN = 20;

int n, q;
int log_2[N];
int pow_2[LOGN];

template<class cmp>
struct stab {
	cmp lt;
	int f[N][LOGN];
	stab(cmp lt) :
			lt(lt) {
	}
	void prep() {
		// invoker should fill f[i][0] first
		for (int j = 1; j <= log_2[n]; ++j) {
			for (int i = 0; i < n; ++i) {
				int j2 = j - 1;
				int i2 = i + pow_2[j2];
				if (i2 >= n) {
					f[i][j] = f[i][j2];
				} else if (lt(f[i][j2], f[i2][j2])) {
					f[i][j] = f[i][j2];
				} else {
					f[i][j] = f[i2][j2];
				}
			}
		}
	}
	int query(int a, int b) {
		int i1 = a;
		int j1 = log_2[b - a + 1];
		int i2 = b - pow_2[j1] + 1;
		int j2 = j1;
		if (lt(f[i1][j1], f[i2][j2]))
			return f[i1][j1];
		else
			return f[i2][j2];
	}
};

void init()
{
    for (int k = 1; k < LOGN; ++k)
        for (int i = (1 << (k - 1)); i < (1 << k) && i < N; ++i)
            log_2[i] = k - 1;
    for (int i = 0; i < LOGN; ++i)
        pow_2[i] = (1 << i);
}

stab<less<int> > small = stab<less<int> >(less<int>());

int a[N];
int g[N];

int main() {
	init();
	scanf("%d", &n);
	for (int i = 0; i < n; ++i) {
		scanf("%d", &a[i]);
		small.f[i][0] = a[i];
	}
    small.prep();

	for (int i = 0; i < n; ++i) {
		int x, y;
		int L = 0;
		int R = i;
		while (L < R) {
			int mid = (L + R) >> 1;
			int q = small.query(mid, i);
			if (q < a[i]) {
				L = mid + 1;
			} else {
				R = mid;
			}
		}
		x = R;

		L = i;
		R = n - 1;
		while (L < R) {
			int mid = (L + R + 1) >> 1;
			int q = small.query(i, mid);
			if (q < a[i]) {
				R = mid - 1;
			} else {
				L = mid;
			}
		}
		y = L;
		//cout << a[i] << " " << x << " " << y << endl;
		g[y - x + 1] = max(g[y - x + 1], a[i]);
	}
	for (int i = 2; i <= N; ++i) {
		if (g[i] > 0) {
			int j = i;
			while (j > 0 && g[j] >= g[j - 1]) {
				g[j - 1] = g[j];
				--j;
			}
		}
	}
	for (int i = 1; i <= n; ++i) {
		cout << g[i] << " ";
	}
	cout << endl;
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll seg[400001];
int arr[100001];
int n;
void build(int node, int l, int r){
    if(l == r){seg[node] = l;return;}
    build(2*node+1, l, (l+r)/2);
    build(2*node+2, (l+r)/2+1, r);
    seg[node] = arr[seg[2*node+1]] < arr[seg[2*node+2]] ? seg[2*node+1] : seg[2*node+2];
}
int mn(int node, int l, int r, int i ,int j){
    if(i > r || j < l)return -1;
    if(l >= i && r <= j)return seg[node];
//    if(l == r)return -1;
    int p1, p2;
    p1 = mn(2*node+1, l, (l+r)/2, i, j);
    p2 = mn(2*node+2, (l+r)/2+1, r, i, j);
    if(p1 == -1)
        return p2;
    else if (p2 == -1)
        return p1;
    else
        return (arr[p1] < arr[p2] ? p1 : p2);
}
int sol[100001];
void solve(int l, int r){
    if(l > r)return;
    int m = mn(0, 0, n-1, l, r);
    for(int i = 0;i < min(m-l, r-m)+1;i++){
        sol[r-l+1-i] = max(arr[m], sol[r-l+1-i]);
    }
    solve(l, m-1);
    solve(m + 1, r);
}

int main() {
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    cin >> n;
    for(int i = 0;i < n;i++)cin >> arr[i];
    build(0, 0, n-1);
    solve(0, n-1);
    for(int i = 1;i <= n;i++)cout << sol[i] << ' ';
}


#include <bits/stdc++.h>
#define ll long long
#define OO 1e9
using namespace std;

int main() {
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    stack<int> st;
    int n;
    cin >> n;
    int sol[200001];
    int arr[200001];
    memset(sol, 0, sizeof(sol));
    int mn = OO;
    for(int i = 0;i < n;i++){cin>>arr[i];mn = min(mn, arr[i]);}
    for(int i = 0;i < n;i++){
        sol[1] = max(sol[1], arr[i]);
        if(st.empty() || arr[st.top()] <= arr[i]){
            st.push(i);
            continue;
        }
        while(st.size() && arr[st.top()] > arr[i]){
            int x = st.top();st.pop();
            sol[st.empty() ? i : i - st.top() - 1] = max(arr[x], sol[st.empty() ? i : i - st.top() - 1]);
        }
        st.push(i);
    }
    while(st.size()){
        int x = st.top();st.pop();
        sol[st.empty() ? n : n - st.top() - 1] = max(arr[x], sol[st.empty() ? n : n - st.top() - 1]);
    }
    int i = n;
    for(;!sol[i];i--)sol[i] = mn;
    for(i = min(i, n-1);i >= 1;i--)sol[i] = max(sol[i], sol[i+1]);
    for(int i = 1;i <= n;i++){
        cout << sol[i] << ' ';
    }
}


#include <bits/stdc++.h>
#define ll long long
#define OO 1e9
using namespace std;

int main() {
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    stack<int> st;
    int n;
    cin >> n;
    int sol[200001];
    int arr[200001];
    memset(sol, 0, sizeof(sol));
    int mn = OO;
    for(int i = 0;i < n;i++){cin>>arr[i];mn = min(mn, arr[i]);}
    for(int i = 0;i < n;i++){
        sol[1] = max(sol[1], arr[i]);
        if(st.empty() || arr[st.top()] <= arr[i]){
            st.push(i);
            continue;
        }
        while(st.size() && arr[st.top()] > arr[i]){
            int x = st.top();st.pop();
            sol[st.empty() ? i : i - st.top() - 1] = max(arr[x], sol[st.empty() ? i : i - st.top() - 1]);
        }
        st.push(i);
    }
    while(st.size()){
        int x = st.top();st.pop();
        sol[st.empty() ? n : n - st.top() - 1] = max(arr[x], sol[st.empty() ? n : n - st.top() - 1]);
    }
    int i = n;
    for(;!sol[i];i--)sol[i] = mn;
    for(;i >= 1;i--)sol[i] = max(sol[i], sol[i+1]);
    for(int i = 1;i <= n;i++){
        cout << sol[i] << ' ';
    }
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll seg[800001];
int arr[200001];
int n;
void build(int node, int l, int r){
    if(l == r){seg[node] = l;return;}
    build(2*node+1, l, (l+r)/2);
    build(2*node+2, (l+r)/2+1, r);
    seg[node] = arr[seg[2*node+1]] < arr[seg[2*node+2]] ? seg[2*node+1] : seg[2*node+2];
}
int mn(int node, int l, int r, int i ,int j){
    if(i > r || j < l)return -1;
    if(l >= i && r <= j)return seg[node];
//    if(l == r)return -1;
    int p1, p2;
    p1 = mn(2*node+1, l, (l+r)/2, i, j);
    p2 = mn(2*node+2, (l+r)/2+1, r, i, j);
    if(p1 == -1)
        return p2;
    else if (p2 == -1)
        return p1;
    else
        return (arr[p1] < arr[p2] ? p1 : p2);
}
int sol[200001];
void solve(int l, int r){
    if(l > r)return;
    int m = mn(0, 0, n-1, l, r);
    for(int i = 0;i < min(m-l, r-m)+1;i++){
        sol[r-l+1-i] = max(arr[m], sol[r-l+1-i]);
    }
    solve(l, m-1);
    solve(m + 1, r);
}

int main() {
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    cin >> n;
    for(int i = 0;i < n;i++)cin >> arr[i];
    build(0, 0, n-1);
    solve(0, n-1);
    for(int i = 1;i <= n;i++)cout << sol[i] << ' ';
}


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdlib>
using namespace std;
typedef long long ll;
#define N 200010
int n, a[N], tem[N], ntem;

int b[N], p1[N], ans[N];
void update(int x,int v, int ty){
    for(int i = x; i <= ntem; i += i &-i){
        if(ty == 1) b[i] = max(b[i], v);
        else b[i] = min(b[i], v);
    }
}
int query(int x, int ty){
    int ans = ty == 1? 0 : n + 1;
    for(int i = x; i > 0; i -= i &-i){
        if(ty == 1) ans = max(ans, b[i]);
        else ans = min(ans, b[i]);
    }
    return ans;
}
int main(){
    //freopen("data.txt","r",stdin);
    scanf("%d",&n);
    for(int i = 1; i <= n; i++) scanf("%d",a+i);
    for(int i = 1; i <= n; i++) tem[i] = a[i];
    ntem = n;
    sort(tem + 1, tem + 1 + ntem);
    ntem = (int)(unique(tem + 1, tem + 1 + ntem) - (tem + 1));
    for(int i = 1; i <= n; i++) a[i] = (int)(lower_bound(tem + 1, tem + 1 + ntem, a[i]) - tem);

    for(int i  = 0; i <= ntem; i++) b[i] = 0;
    for(int i = 1; i <= n; i++){
        p1[i] = query(a[i] - 1, 1) + 1;
        update(a[i], i, 1);
    }
    for(int i = 0; i <= ntem; i++) b[i] = n + 1;
    for(int i = n; i >= 1; i--){
        int p2 = query(a[i] - 1, 2) - 1;
        update(a[i], i, 2);
        int maxl = p2 - p1[i] + 1;
        ans[maxl] = max(ans[maxl], tem[a[i]]);
    }
    for(int i = n - 1; i >= 1; i--) ans[i] = max(ans[i], ans[i+1]);
    for(int i = 1; i <= n; i++) printf("%d%c",ans[i], i == n? '\n' : ' ');
    return 0;
}


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdlib>
using namespace std;
typedef long long ll;
#define N 200010
int n, nex[N], vis[N], gr[N], ans[N];
int getnex(int x){
    if(x != nex[x] )  nex[x] = getnex(nex[x]);
    return nex[x];
}
struct Data{
    int h, p;
}d[N];
bool cmp1(const Data a, const Data b){
    if(a.h != b.h) return a.h > b.h;
    else return a.p < b.p;
}
int main(){
    //freopen("data.txt","r",stdin);
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        scanf("%d",&d[i].h);
        d[i].p = i;
    }
    sort(d + 1, d + 1 + n, cmp1);
    for(int i = 1; i <= n; i++) nex[i] = i, vis[i] = 0, gr[i] = 1, ans[i] = 0;
    for(int i = 1; i <= n; i++){
        int nex1, nex2, maxi = gr[d[i].p];
        vis[d[i].p] = 1;
        if(vis[d[i].p - 1])
        {
            nex1 = getnex(d[i].p);
            nex2 = getnex(d[i]. p - 1);
            if(nex1 != nex2)
            {
                nex[nex2] = nex1;
                gr[nex1] += gr[nex2];
                maxi = max(maxi, gr[nex1]);
            }
        }
        if(vis[d[i].p + 1])
        {
            nex1 = getnex(d[i].p);
            nex2 = getnex(d[i]. p + 1);
            if(nex1 != nex2)
            {
                nex[nex2] = nex1;
                gr[nex1] += gr[nex2];
                maxi = max(maxi, gr[nex1]);
            }
        }
        //printf("i = %d h = %d p = %d maxi = %d\n",i,d[i].h,d[i].p,maxi);
        ans[maxi] = max(ans[maxi], d[i].h);
    }
    for(int i = n - 1; i >= 1; i--) ans[i] = max(ans[i], ans[i + 1]);
    for(int i = 1; i <= n; i++) printf("%d%c",ans[i],i==n?'\n':' ');
    return 0;
}


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdlib>
using namespace std;
typedef long long ll;
#define N 200010
int n, a[N], tem[N], ntem;

int b[N], p1[N];
void update1(int x,int v){
    for(int i = x; i <= ntem; i += i &-i){
        b[i] = max(b[i], v);
    }
}
int query1(int x){
    int ans = 0;
    for(int i = x; i > 0; i -= i &-i){
        ans = max(ans, b[i]);
    }
    return ans;
}
void update2(int x,int v){
    for(int i = x; i <= ntem; i += i &-i){
        b[i] = min(b[i], v);
    }
}
int query2(int x){
    int ans = n + 1;
    for(int i = x; i > 0; i -= i &-i){
        ans = min(ans, b[i]);
    }
    return ans;
}

int tr[N << 2], lazy[N << 2];
#define lch id<<1
#define rch id<<1|1
void plant(int id,int l,int r){
    tr[id] = lazy[id] = 0;
    if(l == r) return;
    int mid = (l + r) >> 1;
    plant(lch, l, mid);
    plant(rch, mid + 1, r);
}
void pushdown(int id){
    if(lazy[id] > 0)
    {
        lazy[lch] = max(lazy[lch], lazy[id]);
        tr[lch] = max(tr[lch], lazy[id]);
        lazy[rch] = max(lazy[rch], lazy[id]);
        tr[rch] = max(tr[rch], lazy[id]);
        lazy[id] = 0;
    }
}
void update(int id,int ql,int qr,int l,int r,int v){
    if(ql == l && qr == r){
        lazy[id] = max(lazy[id], v);
        tr[id] = max(tr[id], v);
        return;
    }
    pushdown(id);
    int mid = (l + r) >> 1;
    if(qr <= mid) update(lch, ql, qr, l, mid, v);
    else if(mid < ql) update(rch, ql, qr, mid + 1, r, v);
    else update(lch, ql, mid, l, mid, v), update(rch, mid + 1, qr, mid + 1, r, v);
    tr[id] = max(tr[lch], tr[rch]);
}
int query(int id,int p,int l,int r){
    if(l == r) return tr[id];
    pushdown(id);
    int mid = (l + r) >> 1;
    if(p <= mid) return query(lch, p, l, mid);
    else return query(rch, p, mid + 1, r);
}

int main(){
    scanf("%d",&n);
    for(int i = 1; i <= n; i++) scanf("%d",a+i);
    for(int i = 1; i <= n; i++) tem[i] = a[i];
    ntem = n;
    sort(tem + 1, tem + 1 + ntem);
    ntem = (int)(unique(tem + 1, tem + 1 + ntem) - (tem + 1));
    for(int i = 1; i <= n; i++) a[i] = (int)(lower_bound(tem + 1, tem + 1 + ntem, a[i]) - tem);

    for(int i  = 0; i <= ntem; i++) b[i] = 0;
    for(int i = 1; i <= n; i++){
        p1[i] = query1(a[i] - 1) + 1;
        update1(a[i], i);
    }
    for(int i = 0; i <= ntem; i++) b[i] = n + 1;
    plant(1, 1, n);
    for(int i = n; i >= 1; i--){
        int p2 = query2(a[i] - 1) - 1;
        update2(a[i], i);
        int maxl = p2 - p1[i] + 1;
        int minl = min(i - p1[i] + 1, p2 - i + 1);
        //printf("i = %d a = %d tem = %d l = %d r = %d\n",i,a[i],tem[a[i]],minl,maxl);
        update(1, minl, maxl, 1, n, tem[a[i]]);
    }

    for(int i = 1; i <= n; i++){
        int ans = query(1, i, 1, n);
        printf("%d%c",ans, i == n? '\n' : ' ');
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using D = long double;
const D eps = 1e-11;

#define DEBUG
#ifdef DEBUG
#define dump(...) cerr<<"["<<__LINE__<< "] "<<#__VA_ARGS__<<" = "<<make_tuple(__VA_ARGS__)<<"\n";
template <typename T> ostream &operator<<(ostream &o, const vector<T> &v) { o << '{'; for(int i = 0; i < (int) v.size(); i++) o << v[i] << (i != (int)v.size()-1 ? ", " : ""); o << "}";  return o; }
template<int n, class...T> typename enable_if<(n>=sizeof...(T))>::type _ot(ostream &, tuple<T...> const &){}
template<int n, class...T> typename enable_if<(n< sizeof...(T))>::type _ot(ostream & os, tuple<T...> const & t){ os << (n==0?"":", ") << get<n>(t); _ot<n+1>(os, t); }
template<class...T> ostream & operator<<(ostream & os, tuple<T...> const & t){ _ot<0>(os, t); return os; }
#else
#define dump(...)
#endif

using P = tuple<D, D, int>;
ll ans = 0;

/// --- BIT Library {{{ ///

struct BIT{
  vector<ll> data;
  int n;
  BIT(int n): n(n){
    data.resize(n, 0);
  }
  void clear(int sz=0) {
    if(sz > 0) n = sz;
    data.assign(n, 0);
  }
  void add(int i, ll x) {
    i++;
    while(i<=n){
      data[i-1] += x;
      i += i&-i;
    }
  }
  ll sum(int i) {
    if(i<0) return 0;
    i++;
    ll s = 0;
    while(i>0){
      s += data[i-1];
      i -= i&-i;
    }
    return s;
  }
  ll range(int a, int b) {
    return sum(b) - sum(a-1);
  }
};

/// }}}--- ///

ll bouble(priority_queue<pair<D, int>> &v) {
  int n = v.size();
  BIT tree(n);
  ll res = 0;
  using T = pair<int, int>;
  priority_queue<T, vector<T>, greater<T>> p;
  for(int i = 0; i < n; i++) {
    p.emplace(v.top().second, n - 1 - i);
    v.pop();
  }

  for(int i = 0; i < n; i++) {
    int t = p.top().first, x = p.top().second;
    p.pop();
    res += i - tree.sum(x);
    tree.add(x, 1);
  }
  return res;
}

void calc(priority_queue<pair<int, D>> &p, bool f = 0) {
  int n = p.size();
  priority_queue<pair<D, int>> v;
  for(int i = 0; i < n; i++) {
    D x = p.top().first, vx = p.top().second;
    p.pop();
    if(f) x += vx * 2.1e9;
    else x -= vx * 2.1e9;
    v.emplace(x, n - 1 - i);
  }
  ans += bouble(v) * 2;
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0);
  int n, a, b; cin >> n >> a >> b;
  vector<ll> x(n);
  vector<P> v(n);
  D theta = atan(a);
  for(int i = 0; i < n; i++) {
    D tx, ty;
    cin >> x[i] >> tx >> ty;
    complex<D> c(tx, ty);
    c *= complex<D>(cos(-theta), sin(-theta));
    tx = real(c); ty = imag(c);
    v[i] = P(ty, tx, x[i]);
  }
  sort(begin(v), end(v));
  dump(v);

  D last;
  int f = 1;
  priority_queue<pair<int, D>> xs;
  for(int i = 0; i < n; i++) {
    D vy = get<0>(v[i]), vx = get<1>(v[i]);
    int x = get<2>(v[i]);
    if(f || abs(vy - last) < eps) {
      f = 0;
    } else {
      f = 1;
      auto ts = xs;
      calc(ts);
      calc(xs, 1);
    }
    xs.emplace(x, vx);
    last = vy;
  }
  auto ts = xs;
  calc(ts);
  calc(xs, 1);
  cout << ans << endl;
}


#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using D = double;
const D eps = 1e-10;

#define DEBUG
#ifdef DEBUG
#define dump(...) cerr<<"["<<__LINE__<< "] "<<#__VA_ARGS__<<" = "<<make_tuple(__VA_ARGS__)<<"\n";
template <typename T> ostream &operator<<(ostream &o, const vector<T> &v) { o << '{'; for(int i = 0; i < (int) v.size(); i++) o << v[i] << (i != (int)v.size()-1 ? ", " : ""); o << "}";  return o; }
template<int n, class...T> typename enable_if<(n>=sizeof...(T))>::type _ot(ostream &, tuple<T...> const &){}
template<int n, class...T> typename enable_if<(n< sizeof...(T))>::type _ot(ostream & os, tuple<T...> const & t){ os << (n==0?"":", ") << get<n>(t); _ot<n+1>(os, t); }
template<class...T> ostream & operator<<(ostream & os, tuple<T...> const & t){ _ot<0>(os, t); return os; }
#else
#define dump(...)
#endif

using P = tuple<D, D, int>;
ll ans = 0;

/// --- BIT Library {{{ ///

struct BIT{
  vector<ll> data;
  int n;
  BIT(int n): n(n){
    data.resize(n, 0);
  }
  void clear(int sz=0) {
    if(sz > 0) n = sz;
    data.assign(n, 0);
  }
  void add(int i, ll x) {
    i++;
    while(i<=n){
      data[i-1] += x;
      i += i&-i;
    }
  }
  ll sum(int i) {
    if(i<0) return 0;
    i++;
    ll s = 0;
    while(i>0){
      s += data[i-1];
      i -= i&-i;
    }
    return s;
  }
  ll range(int a, int b) {
    return sum(b) - sum(a-1);
  }
};

/// }}}--- ///

ll bouble(priority_queue<pair<D, int>> &v) {
  int n = v.size();
  BIT tree(n);
  ll res = 0;
  using T = pair<int, int>;
  priority_queue<T, vector<T>, greater<T>> p;
  for(int i = 0; i < n; i++) {
    p.emplace(v.top().second, n - 1 - i);
    v.pop();
  }

  for(int i = 0; i < n; i++) {
    int t = p.top().first, x = p.top().second;
    p.pop();
    res += i - tree.sum(x);
    tree.add(x, 1);
  }
  return res;
}

void calc(priority_queue<pair<int, D>> &p, bool f = 0) {
  int n = p.size();
  priority_queue<pair<D, int>> v;
  for(int i = 0; i < n; i++) {
    D x = p.top().first, vx = p.top().second;
    p.pop();
    if(f) x += vx * 2.1e9;
    else x -= vx * 2.1e9;
    v.emplace(x, n - 1 - i);
  }
  ans += bouble(v) * 2;
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0);
  int n, a, b; cin >> n >> a >> b;
  vector<ll> x(n);
  vector<P> v(n);
  D theta = atan(a);
  for(int i = 0; i < n; i++) {
    D tx, ty;
    cin >> x[i] >> tx >> ty;
    complex<D> c(tx, ty);
    c *= complex<D>(cos(-theta), sin(-theta));
    tx = real(c); ty = imag(c);
    v[i] = P(ty, tx, x[i]);
  }
  sort(begin(v), end(v));
  dump(v);

  D last;
  int f = 1;
  priority_queue<pair<int, D>> xs;
  for(int i = 0; i < n; i++) {
    D vy = get<0>(v[i]), vx = get<1>(v[i]);
    int x = get<2>(v[i]);
    if(f || abs(vy - last) < eps) {
      f = 0;
    } else {
      f = 1;
      auto ts = xs;
      calc(ts);
      calc(xs, 1);
    }
    xs.emplace(x, vx);
    last = vy;
  }
  auto ts = xs;
  calc(ts);
  calc(xs, 1);
  cout << ans << endl;
}


#include <stdio.h>
#include <fstream>
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <tuple>

using namespace std;
typedef long long ll;

#define endl "\n"
#define INF 100000000
#define MOD 1000000007

int Q, N, M, K, L;

struct Deno {
  ll x, y;

  Deno(ll _x, ll _y) {
    x = _x;
    y = _y;
  }

  bool operator<(const Deno& rhs) const {
    return x * rhs.y < rhs.x * y;
  }
};

map<Deno, ll> MAP;
vector < pair<int, ll> > A, B;
vector<ll> C, D;
vector<ll> BIT;

// Returns inversion count in arr[0..n-1]
ll getInvCountSet(vector<ll>& arr)
{
  int n = arr.size();
  if (!n) return 0;
  // Create an empty set and insert first element in it
  set<ll> set1;
  set1.insert(arr[0]);

  ll invcount = 0; // Initialize result
  set<ll>::iterator itset1; // Iterator for the set

                             // Traverse all elements starting from second
  for (int i = 1; i<n; i++)
  {
    // Insert arr[i] in set (Note that set maintains
    // sorted order)
    set1.insert(arr[i]);

    // Set the iterator to first greater element than arr[i]
    // in set (Note that set stores arr[0],.., arr[i-1]
    itset1 = set1.upper_bound(arr[i]);

    // Get distance of first greater element from end
    // and this distance is count of greater elements
    // on left side of arr[i]
    invcount += distance(itset1, set1.end());
  }

  return invcount;
}

int main() {

  cin >> N >> M >> K;

  bool flip = M < 0;
  for (int i = 0; i < N; i++) {
    ll a, b, c;
    cin >> a >> b >> c;
    if (flip) b = b * -1;
    Deno deno = { b,c };
    ll deg = b * c;

    if (deg == 0) {
      if (b == 0) {
        deno = { -1, 3 };
      }
      else {
        deno = { -1, 4 };
      }
    }
    else if (deg % M == 0 && deg > 0) {
      ll vel = b * b + c * c;
      if (b > 0) A.push_back({ a, vel });
      else B.push_back({ a, vel });
    }
    MAP[deno] ++;
  }

  sort(A.begin(), A.end());
  sort(B.begin(), B.end());
  for (int i = 0; i < A.size(); i++) C.push_back(A[i].second);
  for (int i = 0; i < B.size(); i++) D.push_back(B[i].second);

  ll ret = 0;
  for (auto const& x : MAP) {
    ret += x.second * (N - x.second);
  }
  ll inva = getInvCountSet(C);
  ll invb = getInvCountSet(D);
  ret += A.size() * B.size() * 2;
  cout << ret + inva * 2 + invb * 2 << endl;

  cin >> N;

}


#include <stdio.h>
#include <fstream>
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <tuple>

using namespace std;
typedef long long ll;

#define endl "\n"
#define INF 100000000
#define MOD 1000000007

int Q, N, M, K, L;

struct Deno {
  ll x, y;

  Deno(ll _x, ll _y) {
    x = _x;
    y = _y;
  }

  bool operator<(const Deno& rhs) const {
    return x * rhs.y < rhs.x * y;
  }
};

map<Deno, ll> MAP;
vector < pair<int, ll> > A, B;
vector<ll> C, D;
vector<ll> BIT;

// Returns inversion count in arr[0..n-1]
int getInvCountSet(vector<ll>& arr)
{
  int n = arr.size();
  // Create an empty set and insert first element in it
  set<ll> set1;
  set1.insert(arr[0]);

  int invcount = 0; // Initialize result

  set<ll>::iterator itset1; // Iterator for the set

                             // Traverse all elements starting from second
  for (int i = 1; i<n; i++)
  {
    // Insert arr[i] in set (Note that set maintains
    // sorted order)
    set1.insert(arr[i]);

    // Set the iterator to first greater element than arr[i]
    // in set (Note that set stores arr[0],.., arr[i-1]
    itset1 = set1.upper_bound(arr[i]);

    // Get distance of first greater element from end
    // and this distance is count of greater elements
    // on left side of arr[i]
    invcount += distance(itset1, set1.end());
  }

  return invcount;
}

int main() {

  cin >> N >> M >> K;

  bool flip = M < 0;
  for (int i = 0; i < N; i++) {
    ll a, b, c;
    cin >> a >> b >> c;
    if (flip) b = b * -1;
    Deno deno = { b,c };
    ll deg = b * c;

    if (deg == 0) {
      if (b == 0) {
        deno = { -1, 3 };
      }
      else {
        deno = { -1, 4 };
      }
    }
    else if (deg % M == 0) {
      ll vel = b * b + c * c;
      if (b > 0) A.push_back({ a, vel });
      else B.push_back({ a, vel });
    }
    MAP[deno] ++;
  }

  sort(A.begin(), A.end());
  sort(B.begin(), B.end());
  for (int i = 0; i < A.size(); i++) C.push_back(A[i].second);
  for (int i = 0; i < B.size(); i++) D.push_back(B[i].second);

  ll ret = 0;
  for (auto const& x : MAP) {
    ret += x.second * (N - x.second);
  }
  ll inva = getInvCountSet(C);
  ll invb = getInvCountSet(D);
  ret += A.size() * B.size() * 2;
  cout << ret + inva * 2 + invb * 2 << endl;

  cin >> N;

}


#include <stdio.h>
#include <fstream>
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <tuple>

using namespace std;
typedef long long ll;

#define endl "\n"
#define INF 100000000
#define MOD 1000000007

int Q, N, M, K, L;

struct Deno {
  ll x, y;

  Deno(ll _x, ll _y) {
    x = _x;
    y = _y;
  }

  bool operator<(const Deno& rhs) const {
    return x * rhs.y < rhs.x * y;
  }
};

map<Deno, ll> MAP;
vector < pair<int, ll> > A, B;
vector<ll> C, D;
vector<ll> BIT;

ll getSum(vector<ll>& BITree, int index)
{
  ll sum = 0;

  while (index > 0)
  {
    sum += BITree[index];

    index -= index & (-index);
  }
  return sum;
}

void updateBIT(vector<ll>& BITree, int n, int index, ll val)
{
  while (index <= n)
  {
    BITree[index] += val;

    index += index & (-index);
  }
}

int getInvCount(vector<ll>& arr, int n)
{
  ll invcount = 0;

  ll maxElement = 0;
  for (int i = 0; i<n; i++)
    if (maxElement < arr[i])
      maxElement = arr[i];

  BIT.clear();
  BIT.resize(200000 + 1, 0);
  for (int i = 1; i <= maxElement; i++)
    BIT[i] = 0;

  for (int i = n - 1; i >= 0; i--)
  {
    invcount += getSum(BIT, arr[i] - 1);

    updateBIT(BIT, maxElement, arr[i], 1);
  }

  return invcount;
}

int main() {

  cin >> N >> M >> K;

  bool flip = M < 0;
  for (int i = 0; i < N; i++) {
    ll a, b, c;
    cin >> a >> b >> c;
    if (flip) b = b * -1;
    Deno deno = { b,c };
    ll deg = b * c;

    if (deg == 0) {
      if (b == 0) {
        deno = { -1, 3 };
      }
      else {
        deno = { -1, 4 };
      }
    }
    else if (deg % M == 0) {
      ll vel = b * b + c * c;
      if (b > 0) A.push_back({ a, vel });
      else B.push_back({ a, vel });
    }
    MAP[deno] ++;
  }

  sort(A.begin(), A.end());
  sort(B.begin(), B.end());
  for (int i = 0; i < A.size(); i++) C.push_back(A[i].second);
  for (int i = 0; i < B.size(); i++) D.push_back(B[i].second);

  ll ret = 0;
  for (auto const& x : MAP) {
    ret += x.second * (N - x.second);
  }
  ll inva = getInvCount(C, C.size());
  ll invb = getInvCount(D, D.size());
  ret += A.size() * B.size() * 2;
  cout << ret + inva * 2 + invb * 2 << endl;

  cin >> N;

}


#include <stdio.h>
#include <fstream>
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <tuple>

using namespace std;
typedef long long ll;

#define endl "\n"
#define INF 100000000
#define MOD 1000000007

int Q, N, M, K, L;

pair<ll, ll> A[200001];
map< pair<ll, ll>, int > MAP1;
map< ll, int > MAP2;

int main() {

  cin >> N >> M >> K;

  for (int i = 0; i < N; i++) {
    ll a, b, c;
    cin >> a >> b >> c;

    ll p = M * b - c;
    A[i] = { p, b };
    MAP1[{p, b}] ++;
    MAP2[p]++;
  }

  ll ret = 0;
  for (int i = 0; i < N; i++)
    ret += MAP2[A[i].first] - MAP1[A[i]];

  cout << ret;

  cin >> N;

}


#include <stdio.h>
#include <fstream>
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <tuple>

using namespace std;
typedef long long ll;

#define endl "\n"
#define INF 100000000
#define MOD 1000000007

int Q, N, M, K, L;

struct Deno {
  ll x, y;

  Deno(ll _x, ll _y) {
    x = _x;
    y = _y;
  }

  bool operator<(const Deno& rhs) const {
    return x * rhs.y < rhs.x * y;
  }
};

map<Deno, ll> MAP;
vector < pair<int, ll> > A, B;
vector<ll> C, D;
vector<ll> BIT;

// Returns inversion count in arr[0..n-1]
ll getInvCountSet(vector<ll>& arr)
{
  int n = arr.size();
  if (!n) return 0;
  // Create an empty set and insert first element in it
  set<ll> set1;
  set1.insert(arr[0]);

  ll invcount = 0; // Initialize result
  set<ll>::iterator itset1; // Iterator for the set

                             // Traverse all elements starting from second
  for (int i = 1; i<n; i++)
  {
    // Insert arr[i] in set (Note that set maintains
    // sorted order)
    set1.insert(arr[i]);

    // Set the iterator to first greater element than arr[i]
    // in set (Note that set stores arr[0],.., arr[i-1]
    itset1 = set1.upper_bound(arr[i]);

    // Get distance of first greater element from end
    // and this distance is count of greater elements
    // on left side of arr[i]
    invcount += distance(itset1, set1.end());
  }

  return invcount;
}

int main() {

  cin >> N >> M >> K;

  bool flip = M < 0;
  for (int i = 0; i < N; i++) {
    ll a, b, c;
    cin >> a >> b >> c;
    if (flip) b = b * -1;
    Deno deno = { b,c };
    ll deg = b * c;
    Deno ori = { 1, M };

    if (deg == 0) {
      if (b == 0) {
        deno = { -1, 3 };
      }
      else {
        deno = { -1, 4 };
      }
    }
    else if (deno.x * ori.y == deno.y * ori.x && deg > 0) {
      ll vel = b * b + c * c;
      if (b > 0) A.push_back({ a, vel });
      else B.push_back({ a, vel });
    }
    MAP[deno] ++;
  }

  sort(A.begin(), A.end());
  sort(B.begin(), B.end());
  for (int i = 0; i < A.size(); i++) C.push_back(A[i].second);
  for (int i = 0; i < B.size(); i++) D.push_back(B[i].second);

  ll ret = 0;
  for (auto const& x : MAP) {
    ret += x.second * (N - x.second);
  }
  ll inva = getInvCountSet(C);
  ll invb = getInvCountSet(D);
  ret += A.size() * B.size() * 2;
  ret = ret + inva * 2 + invb * 2;
  cout << ret << endl;

  cin >> N;

}


#include <stdio.h>
#include <fstream>
#include <algorithm>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <tuple>

using namespace std;
typedef long long ll;

#define endl "\n"
#define INF 100000000
#define MOD 1000000007

int Q, N, M, K, L;

struct Deno {
  ll x, y;

  Deno(ll _x, ll _y) {
    x = _x;
    y = _y;
  }

  bool operator<(const Deno& rhs) const {
    return x * rhs.y < rhs.x * y;
  }
};

map<Deno, ll> MAP;
vector < pair<int, ll> > A, B;
vector<ll> C, D;
vector<ll> BIT;

// Returns inversion count in arr[0..n-1]
ll getInvCountSet(vector<ll>& arr)
{
  int n = arr.size();
  if (!n) return 0;
  // Create an empty set and insert first element in it
  set<ll> set1;
  set1.insert(arr[0]);

  ll invcount = 0; // Initialize result
  set<ll>::iterator itset1; // Iterator for the set

                             // Traverse all elements starting from second
  for (int i = 1; i<n; i++)
  {
    // Insert arr[i] in set (Note that set maintains
    // sorted order)
    set1.insert(arr[i]);

    // Set the iterator to first greater element than arr[i]
    // in set (Note that set stores arr[0],.., arr[i-1]
    itset1 = set1.upper_bound(arr[i]);

    // Get distance of first greater element from end
    // and this distance is count of greater elements
    // on left side of arr[i]
    invcount += distance(itset1, set1.end());
  }

  return invcount;
}

int main() {

  cin >> N >> M >> K;

  bool flip = M < 0;
  for (int i = 0; i < N; i++) {
    ll a, b, c;
    cin >> a >> b >> c;
    if (flip) b = b * -1;
    Deno deno = { b,c };
    ll deg = b * c;

    if (deg == 0) {
      if (b == 0) {
        deno = { -1, 3 };
      }
      else {
        deno = { -1, 4 };
      }
    }
    else if (deg % M == 0) {
      ll vel = b * b + c * c;
      if (b > 0) A.push_back({ a, vel });
      else B.push_back({ a, vel });
    }
    MAP[deno] ++;
  }

  sort(A.begin(), A.end());
  sort(B.begin(), B.end());
  for (int i = 0; i < A.size(); i++) C.push_back(A[i].second);
  for (int i = 0; i < B.size(); i++) D.push_back(B[i].second);

  ll ret = 0;
  for (auto const& x : MAP) {
    ret += x.second * (N - x.second);
  }
  ll inva = getInvCountSet(C);
  ll invb = getInvCountSet(D);
  ret += A.size() * B.size() * 2;
  cout << ret + inva * 2 + invb * 2 << endl;

  cin >> N;

}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MX=2e5+5;
const double PI=acos(-1.);

ll x[MX], vx[MX], vy[MX];
map< pair<ll,ll>, ll > mp;
vector< double > slope;
vector< ll > baseSlope;

double getSlope(double dx, double dy){
     double rad=atan2(dy, dx);
     if(rad<0) rad+=2.0*PI;
     if(rad>=PI) rad-=PI;
     return rad;
}

int main(){
     ll i, j, k;
     ll n, a, b;
     cin >> n >> a >> b;
     ll still_point=0, ans=0;
     double base=getSlope(1, a);
     for(i=0; i<n; ++i){
          cin >> x[i] >> vx[i] >> vy[i];
          if(vx[i]==0 && vy[i]==0){
               still_point++;
               continue;
          }
          if(getSlope(vx[i], vy[i])==base){
               mp[{vx[i], vy[i]}]++;
               baseSlope.push_back(i);
          }
          slope.push_back(getSlope(vx[i], vy[i]));
     }
     sort(slope.begin(), slope.end());
     ans+=slope.size()*(slope.size()-1);
     for(i=0; i<slope.size(); ++i){
          ll cnt=1, j=i+1;
          while(j<slope.size() && slope[j]==slope[i]){
               cnt++;
               j++;
               i++;
          }
          ans-=cnt*(cnt-1);
     }
     for(i=0; i<baseSlope.size(); ++i){
          ans+=baseSlope.size()-mp[{vx[i], vy[i]}];
     }
     ans+=baseSlope.size()*still_point;
     cout << ans << endl;
}


#include<bits/stdc++.h>
#define MX 200005
using namespace std;
typedef long long ll;

struct st{
     ll x, y, vx, vy;
};

st s[MX];
ll chk[MX], dir[MX];

vector< ll > v1, v2, v3, v4, v5;
pair< ll,ll > p1[MX], p2[MX], p4[MX], p5[MX];

int main(){
     ll i, j, k;
     ll n, a, b, cnt=0, tx, ty;
     cin >> n >> a >> b;
     for(i=0; i<n; ++i){
          scanf("%lld %lld %lld", &s[i].x, &s[i].vx, &s[i].vy);
          s[i].y=s[i].x*a+b;
          tx=s[i].x+s[i].vx;
          ty=s[i].y+s[i].vy;
          if(ty==tx*a+b){
               chk[i]=1;
               if(tx>s[i].x) dir[i]=1;
               else if(tx<s[i].x) dir[i]=-1;
               else dir[i]=0;
          }
          else{
               v4.push_back(i);
          }
     }
     ll ans=0;
     for(i=0; i<n; ++i){
          if(chk[i]){
               if(dir[i]==1) v1.push_back(i);
               else if(dir[i]==-1) v2.push_back(i);
               else v3.push_back(i);
          }
     }
     ll sz1=v1.size(), sz2=v2.size(), sz3=v3.size(), sz4=v4.size();
     ans+=2LL*sz1*sz2;
     ans+=2LL*sz1*sz3;
     ans+=2LL*sz2*sz3;
     for(i=0; i<sz1; ++i){
          tx=s[v1[i]].vx;
          ty=s[v1[i]].vy;
          p1[i]=make_pair(tx, ty);
     }
     for(i=0; i<sz2; ++i){
          tx=s[v2[i]].vx;
          ty=s[v2[i]].vy;
          p2[i]=make_pair(tx, ty);
     }
     for(i=0; i<sz4; ++i){
          tx=s[v4[i]].vx;
          ty=s[v4[i]].vy;
          if(ty<0 && tx<0) tx*=-1, ty*=-1;
          else if(tx<0 && ty>0) ty*=-1;
          else if(tx>0 && ty<0) tx*=-1;
          p4[i]=make_pair(tx, ty);
     }
     sort(p1, p1+sz1);
     sort(p2, p2+sz2);
     sort(p4, p4+sz4);
     for(i=0; i<sz1; ++i){
          cnt=0;
          for(j=i; j<sz1; ++j){
               if(p1[i].first==p1[j].first && p1[i].second==p1[j].second) cnt++;
               else break;
          }
          i=j-1;
          ans+=cnt*(sz1-cnt);
     }
     for(i=0; i<sz2; ++i){
          cnt=0;
          for(j=i; j<sz2; ++j){
               if(p2[i].first==p2[j].first && p2[i].second==p2[j].second) cnt++;
               else break;
          }
          i=j-1;
          ans+=cnt*(sz2-cnt);
     }
     for(i=0; i<sz4; ++i){
          cnt=0;
          for(j=i; j<sz4; ++j){
               if(p4[i].first==p4[j].first && p4[i].second==p4[j].second) cnt++;
               else break;
          }
          i=j-1;
          ans+=cnt*(sz4-cnt);
     }
     cout << ans << endl;
}
/*
4 1 0
1 1 -1
2 1 -1
3 -1 1
4 2 -1
*/


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MX=2e5+5;

map< ll, ll > collide;
map< pair<ll,ll>, ll > parallel;

int main(){
     ll i, j, k;
     ll n, a, b;
     cin >> n >> a >> b;
     ll ans=0;
     for(i=0; i<n; ++i){
          ll x, vx, vy;
          cin >> x >> vx >> vy;
          ans+=collide[a*vx-vy]-parallel[{vx, vy}];
          collide[a*vx-vy]++;
          parallel[{vx, vy}]++;
     }
     cout << ans*2 << endl;
}


#include<bits/stdc++.h>
#define MX 200005
using namespace std;
typedef long long ll;

struct st{
     ll x, y, vx, vy;
};

st s[MX];
ll chk[MX], dir[MX];

vector< ll > v1, v2, v3, v4, v5;
pair< ll,ll > p1[MX], p2[MX], p4[MX], p5[MX];

int main(){
     ll i, j, k;
     ll n, a, b, cnt=0, tx, ty;
     cin >> n >> a >> b;
     for(i=0; i<n; ++i){
          scanf("%lld %lld %lld", &s[i].x, &s[i].vx, &s[i].vy);
          s[i].y=s[i].x*a+b;
          tx=s[i].x+s[i].vx;
          ty=s[i].y+s[i].vy;
          if(ty==tx*a+b){
               chk[i]=1;
               if(tx>s[i].x) dir[i]=1;
               else if(tx<s[i].x) dir[i]=-1;
               else dir[i]=0;
          }
          else{
               v4.push_back(i);
          }
     }
     ll ans=0;
     for(i=0; i<n; ++i){
          if(chk[i]){
               if(dir[i]==1) v1.push_back(i);
               else if(dir[i]==-1) v2.push_back(i);
               else v3.push_back(i);
          }
     }
     ll sz1=v1.size(), sz2=v2.size(), sz3=v3.size(), sz4=v4.size();
     ans+=2LL*sz1*sz2;
     ans+=2LL*sz1*sz3;
     ans+=2LL*sz2*sz3;
     for(i=0; i<sz1; ++i){
          tx=s[v1[i]].vx;
          ty=s[v1[i]].vy;
          p1[i]=make_pair(tx, ty);
     }
     for(i=0; i<sz2; ++i){
          tx=s[v2[i]].vx;
          ty=s[v2[i]].vy;
          p2[i]=make_pair(tx, ty);
     }
     for(i=0; i<sz4; ++i){
          tx=s[v4[i]].vx;
          ty=s[v4[i]].vy;
          p4[i]=make_pair(tx, ty);
     }
     sort(p1, p1+sz1);
     sort(p2, p2+sz2);
     sort(p4, p4+sz4);
     for(i=0; i<sz1; ++i){
          cnt=0;
          for(j=i; j<sz1; ++j){
               if(p1[i].first==p1[j].first && p1[i].second==p1[j].second) cnt++;
               else break;
          }
          i=j-1;
          ans+=cnt*(sz1-cnt);
     }
     for(i=0; i<sz2; ++i){
          cnt=0;
          for(j=i; j<sz2; ++j){
               if(p2[i].first==p2[j].first && p2[i].second==p2[j].second) cnt++;
               else break;
          }
          i=j-1;
          ans+=cnt*(sz2-cnt);
     }
     for(i=0; i<sz4; ++i){
          cnt=0;
          for(j=i; j<sz4; ++j){
               if(p4[i].first==p4[j].first && p4[i].second==p4[j].second) cnt++;
               else break;
          }
          i=j-1;
          ans+=cnt*(sz4-cnt);
     }
     cout << ans << endl;
}


#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <cstring>
#include <iterator>
#include <cmath>
#include <unordered_set>
#include <unordered_map>
#include <bitset>
#include <chrono>

#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma GCC optimize("unroll-loops")

using namespace std;
typedef long long mt;

template<typename T>
constexpr mt infValue = std::is_same<T, int>::value ? 2000100007 : 8600000000000000007ll;
template<typename T>
constexpr mt maxValue = std::is_same<T, int>::value ? 1000000007 : 1000000000000000001ll;

#define rep(a, b, i) for(register mt i = a; i < b; ++i)
#define repe(a, b, i) for(register mt i = a; i <= b; ++i)
#define repd(a, b, i) for(register mt i = a; i > b; --i)
#define repde(a, b, i) for(register mt i = a; i >= b; --i)

const mt INF = infValue<mt>;
const long long MOD = 1000000007ll;
const double EPS = 1e-6;
const mt MAX = maxValue<mt>;

#define N 200111
#define K 5001
#define P 18
#define M (2000111)

mt gcd(mt a, mt b) {
	return b ? gcd(b, a % b) : a;
}

mt n, a, b;
mt x, vx, vy;
map<mt, map<pair<mt, mt>, mt>> m;
mt answ;
int main(void)
{
#ifdef _DEBUG
	freopen("in.txt", "r", stdin);
#endif
	scanf("%lld %lld %lld", &n, &a, &b);
	while (n--)
		scanf("%lld %lld %lld", &x, &vx, &vy), ++m[a * vx - vy][{vx, vy}];
	for (auto v : m) {
		mt c = 0;
		for (auto vp : v.second)  c += vp.second;
		for (auto vp : v.second) {
			mt cnt = c - vp.second;
			answ += cnt * (cnt - 1) * vp.second;
		}
	}
	printf("%lld\n", answ);

	return 0;
}


#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <cstring>
#include <iterator>
#include <cmath>
#include <unordered_set>
#include <unordered_map>
#include <bitset>
#include <chrono>

#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma GCC optimize("unroll-loops")

using namespace std;
typedef long long mt;

template<typename T>
constexpr mt infValue = std::is_same<T, int>::value ? 2000100007 : 8600000000000000007ll;
template<typename T>
constexpr mt maxValue = std::is_same<T, int>::value ? 1000000007 : 1000000000000000001ll;

#define rep(a, b, i) for(register mt i = a; i < b; ++i)
#define repe(a, b, i) for(register mt i = a; i <= b; ++i)
#define repd(a, b, i) for(register mt i = a; i > b; --i)
#define repde(a, b, i) for(register mt i = a; i >= b; --i)

const mt INF = infValue<mt>;
const long long MOD = 1000000007ll;
const double EPS = 1e-6;
const mt MAX = maxValue<mt>;

#define N 200111
#define K 5001
#define P 18
#define M (2000111)

mt n, a, b;
mt x, vx, vy;
map<mt, mt> m;
map<pair<mt, mt>, mt> mx;
mt answ;
int main(void)
{
#ifdef _DEBUG
	freopen("in.txt", "r", stdin);
#endif
	scanf("%lld %lld %lld", &n, &a, &b);
	while (n--)
		scanf("%lld %lld %lld", &x, &vx, &vy), answ += m[a * vx - vy]++ - mx[{vx, vy}]++;
	printf("%lld\n", answ << 1);

	return 0;
}


#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <cstring>
#include <iterator>
#include <cmath>
#include <unordered_set>
#include <unordered_map>
#include <bitset>
#include <chrono>

#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma GCC optimize("unroll-loops")

using namespace std;
typedef long long mt;

template<typename T>
constexpr mt infValue = std::is_same<T, int>::value ? 2000100007 : 8600000000000000007ll;
template<typename T>
constexpr mt maxValue = std::is_same<T, int>::value ? 1000000007 : 1000000000000000001ll;

#define rep(a, b, i) for(register mt i = a; i < b; ++i)
#define repe(a, b, i) for(register mt i = a; i <= b; ++i)
#define repd(a, b, i) for(register mt i = a; i > b; --i)
#define repde(a, b, i) for(register mt i = a; i >= b; --i)

const mt INF = infValue<mt>;
const long long MOD = 1000000007ll;
const double EPS = 1e-6;
const mt MAX = maxValue<mt>;

#define N 200111
#define K 5001
#define P 18
#define M (2000111)

mt gcd(mt a, mt b) {
	return b ? gcd(b, a % b) : a;
}

mt n, a, b;
mt x, vx, vy;
map<mt, map<pair<mt, mt>, mt>> m;
mt answ;
int main(void)
{
#ifdef _DEBUG
	freopen("in.txt", "r", stdin);
#endif
	scanf("%lld %lld %lld", &n, &a, &b);
	while (n--)
		scanf("%lld %lld %lld", &x, &vx, &vy), ++m[a * vx - vy][{vx, vy}];
	for (auto v : m) {
		mt c = 0;
		for (auto vp : v.second)  c += vp.second;
		for (auto vp : v.second) {
			mt cnt = c - vp.second;
			answ += cnt * vp.second;
		}
	}
	printf("%lld\n", answ);

	return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define mp make_pair
#define MAXN 4004
#define INF 1000000000
using namespace std;
int n , a , b;
int x[200000] , vx[200000] , vy[200000];
int gcd(int a , int b)
{
	if(!a)
		return b;
	return gcd(b % a , a);
}
map<pair<int , int> , int> M;
map<pair<int , int> , int> M2;

int main()
{
	ios_base::sync_with_stdio(0);
	cin >> n >> a >> b;
	int GCD = gcd(abs(a) , abs(b));
	a /= GCD;
	b /= GCD;
	if(a < 0)
		a *= -1 , b *= -1;
	ll N = n;
	ll cnt = 0;
	ll cnt2 = 0;
	for(int i = 0; i < n; i++)
	{
		cin >> x[i] >> vx[i] >> vy[i];
		if(!vx[i] && !vy[i])
		{
			cnt++;
			N--;
			continue;
		}
		int GCD = gcd(abs(vx[i]) , abs(vy[i]));
		if(!GCD)
			GCD = max(abs(vx[i]) , abs(vy[i]));
		int VX = vx[i] , VY = vy[i];
		vx[i] /= GCD , vy[i] /= GCD;

		if(vx[i] < 0)
			vx[i] *= -1 , vy[i] *= -1;
		if(vx[i] == a && vy[i] == b)
		{
			M2[{VX , VY}]++;
			cnt2++;
		}
		else
			M[{vx[i] , vy[i]}]++;
	}
	//cout << 1 << endl;
	ll ans = 0;
	for(int i = 0; i < n; i++)
	{
		if(vx[i] == a && vy[i] == b)
		{
			ans += cnt;
			ans += n - cnt2;
		}
	}

	for(auto it = M.begin(); it != M.end(); it++)
	{
		ans += it->second * (N - it->second);

	}
	for(auto it = M2.begin(); it != M2.end(); it++)
	{
		ans += it->second * (cnt2 - it->second);

	}
	cout << ans;
	//cout << x << " " << y << endl;

}


#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define mp make_pair
#define FILL(A,value) memset(A,value,sizeof(A))
#define ALL(V) V.begin(), V.end()
#define SZ(V) (int)V.size()
#define PI acos(-1.0)
#define less huess
#define MAXN 4002
#define MAXN1 2000
const int INF = 1000 * 1000 * 1000;
const ll LINF = (ll)INF * INF;
const int mod = INF + 7;

using namespace std;

int n , a , b , x[200000] , vx[200000] , vy[200000];

map<ll  , int> cnt;
map<pair<int , int> , int > byVector;

int gcd(int a , int b)
{

}

ll f(int vx , int vy)
{
	return (ll)a * vx - vy;
}

ll ans = 0;

void input()
{
	cin >> n >> a >> b;

	for(int i = 0; i < n; i++)
	{
		cin >> x[i] >> vx[i] >> vy[i];

		//assert(vx[i] || vy[i]);
	}

	//N = d[n - 1] + 1;

}
void gen()
{

}
void output()
{
	cout << ans;
}
void solve()
{
	for(int i = 0; i < n; i++)
	{
		cnt[f(vx[i] , vy[i])]++;
		byVector[{vx[i] , vy[i]}]++;
	}

	for(int i = 0; i < n; i++)
	{
		int val = cnt[f(vx[i] , vy[i])] - 1;
		int val2 = byVector[{vx[i] , vy[i]}] - 1;
		ans += val - val2;
	}
}

bool check()
{

}

void outputInput()
{

}

void clear()
{

}

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

	//freopen("input.txt" , "r" , stdin);

	input();

	solve();

	output();

}


#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define mp make_pair
#define MAXN 4004
#define INF 1000000000
using namespace std;
int n , a , b;
int x[200000] , vx[200000] , vy[200000];
int gcd(int a , int b)
{
	if(!a)
		return b;
	return gcd(b % a , a);
}
map<pair<int , int> , int> M;
int main()
{
	ios_base::sync_with_stdio(0);
	cin >> n >> a >> b;
	int GCD = gcd(abs(a) , abs(b));
	a /= GCD;
	b /= GCD;
	if(a < 0)
		a *= -1 , b *= -1;
	ll N = n;
	ll cnt = 0;
	for(int i = 0; i < n; i++)
	{
		cin >> x[i] >> vx[i] >> vy[i];
		if(!vx[i] && !vy[i])
		{
			cnt++;
			N--;
			continue;
		}
		int GCD = gcd(abs(vx[i]) , abs(vy[i]));
		if(!GCD)
			GCD = max(abs(vx[i]) , abs(vy[i]));

		vx[i] /= GCD , vy[i] /= GCD;
		if(vx[i] < 0)
			vx[i] *= -1 , vy[i] *= -1;
		M[mp(vx[i] , vy[i])]++;
	}
	ll ans = 0;
	for(int i = 0; i < n; i++)
	{
		if(vx[i] == a && vy[i] == b)
		{
			ans += cnt;
		}
	}

	for(auto it = M.begin(); it != M.end(); it++)
		ans += it->second * (N - it->second);
	cout << ans;
	//cout << x << " " << y << endl;

}


#include<stdio.h>
#include<map>
#define ll long long int
std::map<ll, ll> m1;
std::map<ll, ll> ::iterator it;
int main()
{
	ll n, a, b,i,x,u,v,temp;
	scanf("%lld%lld%lld", &n, &a, &b);
	for (i = 1;i <= n;i++)
	{
		scanf("%lld%lld%lld%lld",&x,&u,&v);
		m1[(a*u) + v]++;
	}
	ll sum = 0;
	for (it = m1.begin();it != m1.end();it++)
	{
		sum += ((it->second)*(it->second-1));
	}
	printf("%lld\n",sum);
    return 0;
}


#include<stdio.h>
#include<map>
#define ll long long int
std::map<ll, ll> m1;
std::map<ll, ll> ::iterator it;
int main()
{
	ll n, a, b,i,x,u,v,temp;
	scanf("%lld%lld%lld", &n, &a, &b);
	for (i = 1;i <= n;i++)
	{
		scanf("%lld%lld%lld",&x,&u,&v);
		m1[(a*u) + v]++;
	}
	ll sum = 0;
	for (it = m1.begin();it != m1.end();it++)
	{
		sum += ((it->second)*(it->second-1));
	}
	printf("%lld\n",sum);
    return 0;
}


#include<stdio.h>
#include<map>
#include<utility>
using namespace std;
#define ll long long int
std::map<ll, ll> m1;
std::map<ll, ll> ::iterator it;
std::map<pair<ll, ll>, ll> m2;
std::map<pair<ll, ll>, ll> ::iterator it1;
int main()
{
	ll n, a, b,i,x,u,v,temp;
	scanf("%lld%lld%lld", &n, &a, &b);
	for (i = 1;i <= n;i++)
	{
		scanf("%lld%lld%lld",&x,&u,&v);
		m1[(a*u) - v]++;
		m2[{u, v}]++;
	}
	ll sum = 0;
	for (it = m1.begin();it != m1.end();it++)
	{
		sum += ((it->second)*(it->second-1));
	}
	for (it1 = m2.begin();it1 != m2.end();it1++)
	{
		sum -= ((it1->second)*(it1->second - 1));
	}
	printf("%lld\n",sum);
    return 0;
}


#include<stdio.h>
#include<map>
#define ll long long int
std::map<ll, ll> m1;
std::map<ll, ll> ::iterator it;
int main()
{
	ll n, a, b,i,x,u,v,temp;
	scanf("%lld%lld%lld", &n, &a, &b);
	for (i = 1;i <= n;i++)
	{
		scanf("%lld%lld%lld",&x,&u,&v);
		m1[(a*u) - v]++;
	}
	ll sum = 0;
	for (it = m1.begin();it != m1.end();it++)
	{
		sum += ((it->second)*(it->second-1));
	}
	printf("%lld\n",sum);
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
typedef pair<ll,ll> pll;
typedef vector<ii> vii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<string> vs;
typedef map<int,int> mpii;
typedef map<string,int> mpsi;
typedef set<int> si;
typedef set<ll> sll;
#define pb push_back
#define INF 1000000000
#define LINF INF*INF
#define all(x) x.begin(),x.end()
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	ll a,b,n; cin>>n>>a>>b;
	map<ll,int> mp;
	map<pair<ll,ll>,int> mp2;
	for(int i=0;i<n;i++)
	{
		ll x,vx,vy;cin>>x>>vx>>vy;
		mp[a*vx-vy]++;
		mp2[{vx,vy}]++;
	}
	ll ans=0;
	for(auto it:mp)
	{
		ans+=it.second*(it.second-1);
	}
	for(auto it:mp2)
	{
		ans-=it.second*(it.second-1);
	}
	cout<<ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
typedef pair<ll,ll> pll;
typedef vector<ii> vii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<string> vs;
typedef map<int,int> mpii;
typedef map<string,int> mpsi;
typedef set<int> si;
typedef set<ll> sll;
#define pb push_back
#define INF 1000000000
#define LINF INF*INF
#define all(x) x.begin(),x.end()
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	ll a,b,n; cin>>n>>a>>b;
	map<ll,ll> mp;
	map<pair<int,int>,int> mp2;
	ll ans=0;
	for(int i=0;i<n;i++)
	{
		int x,vx,vy;cin>>x>>vx>>vy;
		ans+=mp[a*vx-vy]-mp2[{vx,vy}];
		mp[a*vx-vy]++;
		mp2[{vx,vy}]++;
	}
	cout<<2*ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
typedef pair<ll,ll> pll;
typedef vector<ii> vii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<string> vs;
typedef map<int,int> mpii;
typedef map<string,int> mpsi;
typedef set<int> si;
typedef set<ll> sll;
#define pb push_back
#define INF 1000000000
#define LINF INF*INF
#define all(x) x.begin(),x.end()
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	ll a,b,n; cin>>n>>a>>b;
	map<ll,ll> mp;
	map<pair<ll,ll>,ll> mp2;
	ll ans=0;
	for(int i=0;i<n;i++)
	{
		ll x,vx,vy;cin>>x>>vx>>vy;
		ans+=mp[a*vx-vy]-mp2[{vx,vy}];
		mp[a*vx-vy]++;
		mp2[{vx,vy}]++;
	}
	cout<<2*ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
typedef pair<ll,ll> pll;
typedef vector<ii> vii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<string> vs;
typedef map<int,int> mpii;
typedef map<string,int> mpsi;
typedef set<int> si;
typedef set<ll> sll;
#define pb push_back
#define INF 1000000000
#define LINF INF*INF
#define all(x) x.begin(),x.end()
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	ll a,b,n; cin>>n>>a>>b;
	map<ll,ll> mp;
	map<pair<ll,ll>,ll> mp2;
	for(int i=0;i<n;i++)
	{
		ll x,vx,vy;cin>>x>>vx>>vy;
		mp[a*vx-vy]++;
		mp2[{vx,vy}]++;
	}
	ll ans=0;
	for(auto it:mp)
	{
		ans+=it.second*(it.second-1);
	}
	for(auto it:mp2)
	{
		ans-=it.second*(it.second-1);
	}
	cout<<ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;

struct Point{
    int x,y,Vx,Vy;
}points[200009];

map<pii>mp;

int main()
{
    int n,a,b;
    cin>>n>>a>>b;

    for(int i=0;i<n;i++)
    {
        cin>>x>>Vx>>Vy;

        int y=a*x+b;
        points[i]={x,y,Vx,Vy};
        pii data= {x1-x2, V}

    }

}


#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;

struct Point{
    int x,y,Vx,Vy;
}points[200009];

map<int, int>mp;

int main()
{
    int n,a,b,x,Vx,Vy;
    cin>>n>>a>>b;

    for(int i=0;i<n;i++)
    {
        cin>>x>>Vx>>Vy;

        int y=a*x+b;
        points[i]={x,y,Vx,Vy};
        int data= {a*Vx-Vy};

        mp[data]++;
    }

    int tot=0;
    for(int i=0;i<n;i++)
    {
        Point p= points[i];

        int data= a*p.Vx - p.Vy;
        tot+=mp[data]-1;

        printf("i= %d\n",mp[data]);

    }

    cout<<tot<<endl;

}


///Got the idea near the solution, then took help from editorial. I was mis thinking one place

#include<bits/stdc++.h>
#define i64 long long
#define pii pair<i64,i64>
using namespace std;

struct Poi64
{
    i64 x,y,Vx,Vy;
} poi64s[200009];

struct trii
{
    i64 val,vx,vy;

    bool operator< (const trii &p)const
    {
        return 1;
    }
};

map<i64, i64>mp;
map<pii,i64>sim;

int main()
{
    i64 n,a,b,x,Vx,Vy;
    cin>>n>>a>>b;

    i64 cnt=0;

    i64 ans=0;
    for(i64 i=0; i<n; i++)
    {
        cin>>x>>Vx>>Vy;

        i64 y=a*x+b;
        poi64s[i]= {x,y,Vx,Vy};
        i64 data= {a*Vx-Vy};

        mp[data]++;

        sim[{Vx,Vy}]++;

        ans+=mp[data]- sim[{Vx,Vy}];

    }

    cout<<ans*2<<endl;

    for(i64 i=0; i<n; i++)
    {

    }

}


///Got the idea near the solution, then took help from editorial. I was mis thinking one place

#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;

struct Point
{
    int x,y,Vx,Vy;
} points[200009];

struct trii
{
    int val,vx,vy;

    bool operator< (const trii &p)const
    {
        return 1;
    }
};

map<int, int>mp;
map<pii,int>sim;

int main()
{
    int n,a,b,x,Vx,Vy;
    cin>>n>>a>>b;

    int cnt=0;

    int ans=0;
    for(int i=0; i<n; i++)
    {
        cin>>x>>Vx>>Vy;

        int y=a*x+b;
        points[i]= {x,y,Vx,Vy};
        int data= {a*Vx-Vy};

        mp[data]++;

        sim[{Vx,Vy}]++;

        ans+=mp[data]- sim[{Vx,Vy}];

    }

    cout<<ans*2<<endl;

    for(int i=0; i<n; i++)
    {

    }

}


//ALEX ENACHE

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#include <unordered_map>
#include <time.h>
#include <iomanip>
#include <deque>
#include <cmath>

using namespace std;

long long v[200100];
long long vv[200100];
map < long long , long long > M;
map < long long , long long > MM;

int main () {

    ios::sync_with_stdio (false);
    cin.tie (NULL);
    cout.tie (NULL);

    //freopen("input" , "r" , stdin);
    //freopen("output" , "w" , stdout);

    long long n , a , b;
    cin>>n>>a>>b;

    for (int i=1; i<=n; i++){
        long long x , vx , vy;
        cin>>x>>vx>>vy;
        vx *= a;
        v[i] = vy - vx;
        vv[i] = vx;
        MM[vx]++;
        M[v[i]]++;
    }

    long long cont = 0;

    for (int i=1; i<=n; i++){
        cont += M[v[i]] - MM[vv[i]];
    }

    cout<<cont;

    return 0;
}


#include <iostream>
#include <stdio.h>

using namespace std;

long long x[200100];
long long y[200100];
long long vx[200100];
long long vy[200100];

int main()
{

    //freopen ("input" , "r" , stdin);
    //freopen ("output" , "w" , stdout);

    ios::sync_with_stdio(false);
    cin.tie(NULL);

    long long n , a , b;
    cin>>n>>a>>b;

    for (int i=1; i<=n; i++){
        cin>>x[i]>>vx[i]>>vy[i];
        y[i] = x[i] * a + b;
    }

    long long cont = 0;

    for (int i=1; i<=n; i++){
        for (int j=1; j<=n; j++){
            if (i == j){
                continue;
            }
            if (vy[j] - vy[i] == 0){
                continue;
            }
            if (vx[j] - vx[i] == 0){
                continue;
            }

            long long one = (x[i] - x[j]) * (vy[j] - vy[i]);
            long long two = (y[i] - y[j]) * (vx[j] - vx[i]);

            //cout<<i<<" "<<j<<" "<<one<<" "<<two<<'\n';

            if (one == two){
                cont++;
            }
        }
    }

    cout<<cont;

    return 0;
}


//ALEX ENACHE

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#include <unordered_map>
#include <time.h>
#include <iomanip>
#include <deque>
#include <cmath>

using namespace std;

long long v[200100];
pair < long long , long long > vv[200100];
map < long long , long long > M;
map < pair<long long  , long long> , long long > MM;

int main () {

    ios::sync_with_stdio (false);
    cin.tie (NULL);
    cout.tie (NULL);

    //freopen("input" , "r" , stdin);
    //freopen("output" , "w" , stdout);

    long long n , a , b;
    cin>>n>>a>>b;

    for (int i=1; i<=n; i++){
        long long x , vx , vy;
        cin>>x>>vx>>vy;
        vx *= a;
        v[i] = vy - vx;
        vv[i] = {vx , vy};
        MM[vv[i]]++;
        M[v[i]]++;
    }

    long long cont = 0;

    for (int i=1; i<=n; i++){
        cont += M[v[i]] - MM[vv[i]];
    }

    cout<<cont;

    return 0;
}


#include <bits/stdc++.h>

#define float double
#define double long double
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;

#define int long long

using namespace std;

const double EPS = 1e-9;
const double PI = acos(-1.0);

typedef ll base;
typedef pair<int, int> point;

int skalar(point a, point b){
    return a.first * b.first + a.second * b.second;

}

int32_t main() {
    int n, a, b;
    cin >> n >> a >> b;

    point gerade;
    gerade.first = 1;
    gerade.second = a;

    map<int, multiset<pair<int, int>>> u;
    ll totalCount = 0;

    int bleibtStehen = 0, aufGeraden = 0;

    for(int i = 0; i < n; i++){
        int xi, vxi, vyi;
        cin >> xi >> vxi >> vyi;

        if(vxi == 0 && vyi == 0){
            bleibtStehen++;
            continue;
        }
        if(vxi * gerade.second == vyi * gerade.first) aufGeraden++;

        //point w;
        //w.first = vxi;
        //w.second = vyi;

        int ergebnis = gerade.second * vxi - gerade.first * vyi;

    	totalCount += u[ergebnis].size()
            - u[ergebnis].count(make_pair(vxi, vyi));
        u[ergebnis].insert(make_pair(vxi, vyi));

  //      int skal = skalar(w, v);

        /*point toll;
        toll.first = w.first - skalar * v.first;
        toll.second = w.second - skalar * v.second;

        int betrag = toll.first * toll.first + toll.second * toll.second;

        mapping[betrag].insert(w);
*/
    }

    //debug(laufAufGeraden);

    totalCount += bleibtStehen * aufGeraden;

    cout << totalCount * 2<< endl;

}


#include <bits/stdc++.h>

#define float double
#define double long double
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;

#define int long long

using namespace std;

const double EPS = 1e-9;
const double PI = acos(-1.0);

typedef ll base;
typedef pair<int, int> point;

int skalar(point a, point b){
    return a.first * b.first + a.second * b.second;

}

map<pair<int, int>, int> asdf[200000];
int asdftot[200000];
int asdfc = 0;

int32_t main() {
    ios::sync_with_stdio(0);

    int n, a, b;
    scanf("%lld %lld %lld", &n, &a, &b);

    point gerade;
    gerade.first = 1;
    gerade.second = a;

    unordered_map<int, int> u;
    ll totalCount = 0;

    int bleibtStehen = 0, aufGeraden = 0;

    for(int i = 0; i < n; i++){
        int xi, vxi, vyi;
        scanf("%lld %lld %lld", &xi, &vxi, &vyi);

        if(vxi == 0 && vyi == 0){
            bleibtStehen++;
            continue;
        }
        if(vxi * gerade.second == vyi * gerade.first) aufGeraden++;

        //point w;
        //w.first = vxi;
        //w.second = vyi;

        int ergebnis = gerade.second * vxi - gerade.first * vyi;

        if (u.count(ergebnis) == 0)  u[ergebnis] = asdfc++;

        map<pair<int, int>, int> &f = asdf[u[ergebnis]];
    	totalCount += asdftot[u[ergebnis]] - f[make_pair(vxi, vyi)];
        f[make_pair(vxi, vyi)]++;
        asdftot[u[ergebnis]]++;

  //      int skal = skalar(w, v);

        /*point toll;
        toll.first = w.first - skalar * v.first;
        toll.second = w.second - skalar * v.second;

        int betrag = toll.first * toll.first + toll.second * toll.second;

        mapping[betrag].insert(w);
*/
    }

    //debug(laufAufGeraden);

    totalCount += bleibtStehen * aufGeraden;

    cout << totalCount * 2<< endl;

}


#include <bits/stdc++.h>

#define float double
#define double long double
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;

#define int long long

using namespace std;

const double EPS = 1e-9;
const double PI = acos(-1.0);

typedef ll base;
typedef pair<int, int> point;

int skalar(point a, point b){
    return a.first * b.first + a.second * b.second;

}

multiset<pair<int, int>> asdf[200000];
int asdfc = 0;

int32_t main() {
    int n, a, b;
    cin >> n >> a >> b;

    point gerade;
    gerade.first = 1;
    gerade.second = a;

    map<int, int> u;
    ll totalCount = 0;

    int bleibtStehen = 0, aufGeraden = 0;

    for(int i = 0; i < n; i++){
        int xi, vxi, vyi;
        cin >> xi >> vxi >> vyi;

        if(vxi == 0 && vyi == 0){
            bleibtStehen++;
            continue;
        }
        if(vxi * gerade.second == vyi * gerade.first) aufGeraden++;

        //point w;
        //w.first = vxi;
        //w.second = vyi;

        int ergebnis = gerade.second * vxi - gerade.first * vyi;

        if (u.count(ergebnis) == 0)
            u[ergebnis] = asdfc++;
    	totalCount += asdf[u[ergebnis]].size()
            - asdf[u[ergebnis]].count(make_pair(vxi, vyi));
        asdf[u[ergebnis]].insert(make_pair(vxi, vyi));

  //      int skal = skalar(w, v);

        /*point toll;
        toll.first = w.first - skalar * v.first;
        toll.second = w.second - skalar * v.second;

        int betrag = toll.first * toll.first + toll.second * toll.second;

        mapping[betrag].insert(w);
*/
    }

    //debug(laufAufGeraden);

    totalCount += bleibtStehen * aufGeraden;

    cout << totalCount * 2<< endl;

}


#include <bits/stdc++.h>

#define float double
#define double long double
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;

#define int long long

using namespace std;

const double EPS = 1e-9;
const double PI = acos(-1.0);

typedef ll base;
typedef pair<int, int> point;

int skalar(point a, point b){
    return a.first * b.first + a.second * b.second;

}

multiset<pair<int, int>> asdf[200000];
int asdfc = 0;

int32_t main() {
    ios::sync_with_stdio(0);

    int n, a, b;
    scanf("%lld %lld %lld", &n, &a, &b);

    point gerade;
    gerade.first = 1;
    gerade.second = a;

    map<int, int> u;
    ll totalCount = 0;

    int bleibtStehen = 0, aufGeraden = 0;

    for(int i = 0; i < n; i++){
        int xi, vxi, vyi;
        scanf("%lld %lld %lld", &xi, &vxi, &vyi);

        if(vxi == 0 && vyi == 0){
            bleibtStehen++;
            continue;
        }
        if(vxi * gerade.second == vyi * gerade.first) aufGeraden++;

        //point w;
        //w.first = vxi;
        //w.second = vyi;

        int ergebnis = gerade.second * vxi - gerade.first * vyi;

        if (u.count(ergebnis) == 0)  u[ergebnis] = asdfc++;

        multiset<pair<int, int>> &f = asdf[u[ergebnis]];
    	totalCount += f.size() - f.count(make_pair(vxi, vyi));
        f.insert(make_pair(vxi, vyi));

  //      int skal = skalar(w, v);

        /*point toll;
        toll.first = w.first - skalar * v.first;
        toll.second = w.second - skalar * v.second;

        int betrag = toll.first * toll.first + toll.second * toll.second;

        mapping[betrag].insert(w);
*/
    }

    //debug(laufAufGeraden);

    totalCount += bleibtStehen * aufGeraden;

    cout << totalCount * 2<< endl;

}


#include <bits/stdc++.h>

#define float double
#define double long double
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;

#define int long long

using namespace std;

const double EPS = 1e-9;
const double PI = acos(-1.0);

typedef ll base;
typedef pair<int, int> point;

int skalar(point a, point b){
    return a.first * b.first + a.second * b.second;

}

multiset<pair<int, int>> asdf[200000];
int asdfc = 0;

int32_t main() {
    ios::sync_with_stdio(0);

    int n, a, b;
    scanf("%lld %lld %lld", &n, &a, &b);

    point gerade;
    gerade.first = 1;
    gerade.second = a;

    map<int, int> u;
    ll totalCount = 0;

    int bleibtStehen = 0, aufGeraden = 0;

    for(int i = 0; i < n; i++){
        int xi, vxi, vyi;
        scanf("%lld %lld %lld", &xi, &vxi, &vyi);

        if(vxi == 0 && vyi == 0){
            bleibtStehen++;
            continue;
        }
        if(vxi * gerade.second == vyi * gerade.first) aufGeraden++;

        //point w;
        //w.first = vxi;
        //w.second = vyi;

        int ergebnis = gerade.second * vxi - gerade.first * vyi;

        int &g = u[ergebnis];
        if (asdf[g].empty())  g = asdfc++;

        multiset<pair<int, int>> &f = asdf[g];
    	totalCount += f.size() - f.count(make_pair(vxi, vyi));
        f.insert(make_pair(vxi, vyi));

  //      int skal = skalar(w, v);

        /*point toll;
        toll.first = w.first - skalar * v.first;
        toll.second = w.second - skalar * v.second;

        int betrag = toll.first * toll.first + toll.second * toll.second;

        mapping[betrag].insert(w);
*/
    }

    //debug(laufAufGeraden);

    totalCount += bleibtStehen * aufGeraden;

    cout << totalCount * 2<< endl;

}


#include <bits/stdc++.h>

#define float double
#define double long double
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;

#define int long long

using namespace std;

const double EPS = 1e-9;
const double PI = acos(-1.0);

typedef ll base;
typedef pair<int, int> point;

int skalar(point a, point b){
    return a.first * b.first + a.second * b.second;

}

int32_t main() {
    int n, a, b;
    cin >> n >> a >> b;

    point gerade;
    gerade.first = 1;
    gerade.second = a;

    map<int, multiset<pair<int, int>>> u;
    ll totalCount = 0;

    int bleibtStehen = 0;
    multiset<int> aufGeraden;

    for(int i = 0; i < n; i++){
        int xi, vxi, vyi;
        cin >> xi >> vxi >> vyi;

        if(vxi == 0 && vyi == 0){
            bleibtStehen++;
            continue;
        }
        if(vxi * gerade.second == vyi * gerade.first){
            totalCount += aufGeraden.size() - aufGeraden.count(vxi);

            aufGeraden.insert(vxi);
            continue;
        }

        //point w;
        //w.first = vxi;
        //w.second = vyi;

        int ergebnis = gerade.second * vxi - gerade.first * vyi;

    	totalCount += u[ergebnis].size()
            - u[ergebnis].count(make_pair(vxi, vyi));
        u[ergebnis].insert(make_pair(vxi, vyi));

  //      int skal = skalar(w, v);

        /*point toll;
        toll.first = w.first - skalar * v.first;
        toll.second = w.second - skalar * v.second;

        int betrag = toll.first * toll.first + toll.second * toll.second;

        mapping[betrag].insert(w);
*/
    }

    //debug(laufAufGeraden);

    totalCount += bleibtStehen * aufGeraden.size();

    cout << totalCount * 2<< endl;

}


#include <bits/stdc++.h>

#define float double
#define double long double
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;

#define int long long

using namespace std;

const double EPS = 1e-9;
const double PI = acos(-1.0);

typedef ll base;
typedef pair<int, int> point;

int skalar(point a, point b){
    return a.first * b.first + a.second * b.second;

}

int32_t main() {
    int n, a, b;
    cin >> n >> a >> b;

    point gerade;
    gerade.first = 1;
    gerade.second = a;

    multiset<int> u;
    ll totalCount = 0;

    int bleibtStehen = 0;
    multiset<int> aufGeraden;

    for(int i = 0; i < n; i++){
        int xi, vxi, vyi;
        cin >> xi >> vxi >> vyi;

        if(vxi == 0 && vyi == 0){
            bleibtStehen++;
            continue;
        }
        if(vxi * gerade.second == vyi * gerade.first){
            totalCount += aufGeraden.size() - aufGeraden.count(vxi);

            aufGeraden.insert(vxi);
            continue;
        }

        //point w;
        //w.first = vxi;
        //w.second = vyi;

        int ergebnis = gerade.second * vxi - gerade.first * vyi;

    	totalCount += u.count(ergebnis);
        u.insert(ergebnis);

  //      int skal = skalar(w, v);

        /*point toll;
        toll.first = w.first - skalar * v.first;
        toll.second = w.second - skalar * v.second;

        int betrag = toll.first * toll.first + toll.second * toll.second;

        mapping[betrag].insert(w);
*/
    }

    //debug(laufAufGeraden);

    totalCount += bleibtStehen * aufGeraden.size();

    cout << totalCount * 2<< endl;

}


#include <bits/stdc++.h>

#define float double
#define double long double
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;

#define int long long

using namespace std;

const double EPS = 1e-9;
const double PI = acos(-1.0);

typedef ll base;
typedef pair<int, int> point;

int skalar(point a, point b){
    return a.first * b.first + a.second * b.second;

}

multiset<pair<int, int>> asdf[200000];
int asdfc = 0;

int32_t main() {
    ios::sync_with_stdio(0);

    int n, a, b;
    scanf("%lld %lld %lld", &n, &a, &b);

    point gerade;
    gerade.first = 1;
    gerade.second = a;

    unordered_map<int, int> u;
    ll totalCount = 0;

    int bleibtStehen = 0, aufGeraden = 0;

    for(int i = 0; i < n; i++){
        int xi, vxi, vyi;
        scanf("%lld %lld %lld", &xi, &vxi, &vyi);

        if(vxi == 0 && vyi == 0){
            bleibtStehen++;
            continue;
        }
        if(vxi * gerade.second == vyi * gerade.first) aufGeraden++;

        //point w;
        //w.first = vxi;
        //w.second = vyi;

        int ergebnis = gerade.second * vxi - gerade.first * vyi;

        if (u.count(ergebnis) == 0)  u[ergebnis] = asdfc++;

        multiset<pair<int, int>> &f = asdf[u[ergebnis]];
    	totalCount += f.size() - f.count(make_pair(vxi, vyi));
        f.insert(make_pair(vxi, vyi));

  //      int skal = skalar(w, v);

        /*point toll;
        toll.first = w.first - skalar * v.first;
        toll.second = w.second - skalar * v.second;

        int betrag = toll.first * toll.first + toll.second * toll.second;

        mapping[betrag].insert(w);
*/
    }

    //debug(laufAufGeraden);

    totalCount += bleibtStehen * aufGeraden;

    cout << totalCount * 2<< endl;

}


#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <sstream>
#include <unordered_map>
#include <vector>

#define INF 4000000000000000000LL
#define MOD 1000000007
#define ALL(x) std::begin(x), std::end(x)

int main(int argc, char** argv)
{
  std::cin.tie(0);
  std::ios_base::sync_with_stdio(0);

  std::cout << std::fixed << std::setprecision(6);
  std::cerr << std::fixed << std::setprecision(6);

  int n;

  long long a, b, x, vx[222222], vy[222222], C = 0;

  std::cin >> n >> a >> b;

  long long Tx = 1, Ty =  a;
  long long Px = a, Py = -1;

  std::map<long long, std::map<long long, int>> map;

  for (int i = 0; i < n; i ++) {
    std::cin >> x >> vx[i] >> vy[i];

    long long t = vx[i] * Tx + vy[i] * Ty;
    long long p = vx[i] * Px + vy[i] * Py;

    map[p][t] ++;
  }

  for (auto& kv : map) {
    int size = 0;

    for (const auto& kv2 : kv.second)
      size += kv2.second;

    for (const auto& kv2 : kv.second)
      C += kv2.second * (size - kv2.second);
  }

  std::cout << C << std::endl;

  return 0;
}


#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <sstream>
#include <unordered_map>
#include <vector>

#define INF 4000000000000000000LL
#define MOD 1000000007
#define ALL(x) std::begin(x), std::end(x)

int main(int argc, char** argv)
{
  std::cin.tie(0);
  std::ios_base::sync_with_stdio(0);

  std::cout << std::fixed << std::setprecision(6);
  std::cerr << std::fixed << std::setprecision(6);

  int n;

  long long a, b, x, vx, vy, C = 0;

  std::cin >> n >> a >> b;

  long long Tx = 1, Ty =  a;
  long long Px = a, Py = -1;

  std::map<long long, std::map<long long, long long>> map;

  for (int i = 0; i < n; i ++) {
    std::cin >> x >> vx >> vy;

    long long t = vx * Tx + vy * Ty;
    long long p = vx * Px + vy * Py;

    map[p][t] ++;
  }

  for (auto& kv : map) {
    long long size = 0;

    for (const auto& kv2 : kv.second)
      size += kv2.second;

    for (const auto& kv2 : kv.second)
      C += kv2.second * (size - kv2.second);
  }

  std::cout << C << std::endl;

  return 0;
}


#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <sstream>
#include <unordered_map>
#include <vector>

#define INF 4000000000000000000LL
#define MOD 1000000007
#define ALL(x) std::begin(x), std::end(x)

int main(int argc, char** argv)
{
  std::cin.tie(0);
  std::ios_base::sync_with_stdio(0);

  std::cout << std::fixed << std::setprecision(6);
  std::cerr << std::fixed << std::setprecision(6);

  int n;

  long long a, b, x, vx[222222], vy[222222], C = 0;

  std::cin >> n >> a >> b;

  long long Tx = 1, Ty =  a;
  long long Px = a, Py = -1;

  std::map<long long, std::map<long long, long long>> map;

  for (int i = 0; i < n; i ++) {
    std::cin >> x >> vx[i] >> vy[i];

    long long t = vx[i] * Tx + vy[i] * Ty;
    long long p = vx[i] * Px + vy[i] * Py;

    map[p][t] ++;
  }

  for (auto& kv : map) {
    long long size = 0;

    for (const auto& kv2 : kv.second)
      size += kv2.second;

    for (const auto& kv2 : kv.second)
      C += kv2.second * (size - kv2.second);
  }

  std::cout << C << std::endl;

  return 0;
}


#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <sstream>
#include <unordered_map>
#include <vector>

#define INF 4000000000000000000LL
#define MOD 1000000007
#define ALL(x) std::begin(x), std::end(x)

int n;

long long a, b, x[222222], vx[222222], vy[222222], t[222222], C = 0;

template<typename T>
class compress_fn_t {
public:
  void add(T x) {
    if (! map_.count(x))
      map_[x] = 0;
  };

public:
  void clear() {
    map_.clear();
  };

public:
  std::pair<std::map<T, int>, std::vector<T>> get() {
    int size = map_.size(), i = 0;

    std::pair<std::map<T, int>, std::vector<T>> pair;

    pair.second.resize(size);

    for (auto& kv : map_) {
      kv.second = i;

      pair.second[i] = kv.first;

      i ++;
    }

    pair.first = map_;

    return std::move(pair);
  };

private:
  std::map<T, int> map_;
};

template<typename T>
class segment_tree_t {
public:
  segment_tree_t(int size = 0) : all_(NULL), part_(NULL)
  {
    resize(size);
  };

  ~segment_tree_t() {
  };

public:
  void resize(int size) {
    for (size_ = 1; size_ < size; size_ <<= 1)
      ;

    all_  = (pall_  = std::shared_ptr<T>(new T[size_ * 2], std::default_delete<T[]>())).get();
    part_ = (ppart_ = std::shared_ptr<T>(new T[size_ * 2], std::default_delete<T[]>())).get();

    memset(all_,  0, sizeof(T) * size_ * 2);
    memset(part_, 0, sizeof(T) * size_ * 2);
  };

public:
  void add(int a, int b, T x, int k = -1, int l = -1, int r = -1) {	// [a, b), 0-index
    if (k == -1) {
      add(a, b, x, 0, 0, size_);
    }
    else {
      if (a <= l && r <= b) {
        all_[k] += x;
      }
      else if (l < b && a < r) {
        part_[k] += (std::min(b, r) - std::max(a, l)) * x;

        add(a, b, x, k * 2 + 1, l, (l + r) / 2);
        add(a, b, x, k * 2 + 2, (l + r) / 2, r);
      }
    }
  };

  T query(int a, int b, int k = -1, int l = -1, int r = -1) const {	// [a, b), 0-index
    if (k == -1) {
      return query(a, b, 0, 0, size_);
    }
    else {
      if (b <= l || r <= a) {
        return 0;
      }
      else if (a <= l && r <= b) {
        return all_[k] * (r - l) + part_[k];
      }
      else {
        T s = (std::min(b, r) - std::max(a, l)) * all_[k];

        s += query(a, b, k * 2 + 1, l, (l + r) / 2);
        s += query(a, b, k * 2 + 2, (l + r) / 2, r);

        return s;
      }
    };
  };

private:
  int size_;

  std::shared_ptr<T> pall_;
  std::shared_ptr<T> ppart_;

  T* all_;
  T* part_;
};

int main(int argc, char** argv)
{
  std::cin.tie(0);
  std::ios_base::sync_with_stdio(0);

  std::cout << std::fixed << std::setprecision(6);
  std::cerr << std::fixed << std::setprecision(6);

  std::cin >> n >> a >> b;

  long long Tx = 1, Ty =  a;
  long long Px = a, Py = -1;

  std::map<long long, std::vector<int>> map;

  for (int i = 0; i < n; i ++) {
    std::cin >> x[i] >> vx[i] >> vy[i];

    t[i] = vx[i] * Tx + vy[i] * Ty;

    long long dot = vx[i] * Px + vy[i] * Py;

    map[dot].push_back(i);
  }

  for (auto& kv : map) {
    std::vector<int>& a = kv.second;

    std::sort(ALL(a), [&](int a, int b) {
        return x[a] < x[b];
      });

    compress_fn_t<long long> fn;

    for (const auto& i : a)
      if (t[i] >= 0)
        fn.add(t[i]);

    auto pair = fn.get();

    int size = pair.first.size();

    {
      segment_tree_t<long long> tree(size);

      long long c = 0;

      for (const auto& i : a)
        if (t[i] < 0) {
          C += c;
        }
        else {
          int x = pair.first[t[i]];

          C += tree.query(x + 1, size);

          tree.add(x, x + 1, 1);

          c ++;
        }
    }

    std::reverse(ALL(a));

    fn.clear();

    for (const auto& i : a)
      if (- t[i] >= 0)
        fn.add(- t[i]);

    pair = fn.get();

    size = pair.first.size();

    {
      segment_tree_t<long long> tree(size);

      long long c = 0;

      for (const auto& i : a) {
        if (- t[i] < 0) {
          ;
        }
        else {
           int x = pair.first[- t[i]];

          C += tree.query(x + 1, size);

          tree.add(x, x + 1, 1);

          c ++;
        }
      }
    }

    std::reverse(ALL(a));

    for (const auto& i : a)
      t[i] = -t[i];

    for (const auto& i : a)
      if (t[i] >= 0)
        fn.add(t[i]);

    pair = fn.get();

    size = pair.first.size();

    {
      segment_tree_t<long long> tree(size);

      long long c = 0;

      for (const auto& i : a)
        if (t[i] < 0) {
          C += c;
        }
        else {
          int x = pair.first[t[i]];

          C += tree.query(x + 1, size);

          tree.add(x, x + 1, 1);

          c ++;
        }
    }

    std::reverse(ALL(a));

    fn.clear();

    for (const auto& i : a)
      if (- t[i] >= 0)
        fn.add(- t[i]);

    pair = fn.get();

    size = pair.first.size();

    {
      segment_tree_t<long long> tree(size);

      long long c = 0;

      for (const auto& i : a) {
        if (- t[i] < 0) {
          ;
        }
        else {
           int x = pair.first[- t[i]];

          C += tree.query(x + 1, size);

          tree.add(x, x + 1, 1);

          c ++;
        }
      }
    }

    std::reverse(ALL(a));
  }

  std::cout << C * 2 << std::endl;

  return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N (int)2e5+10
ll gcd(ll a, ll b)
{
	return b == 0 ? a : gcd(b, a % b);
}
struct f{
	int a, b;
	f(int q, int w)
	{
		int g = abs(gcd(q, w));
		if (g != 0)
		{
			a = q / g;
			b = w / g;
		}
		else
		{
			a = q, b = w;
		}
	}
	bool operator< (const f &c) const
	{
		if (a != c.a) return a < c.a;
		else return b < c.b;
	}
};
map<f, ll> mp;

int main(void)
{
	ll n;
	ll a, b;
	cin >> n >> a >> b;
	int i;
	for (i = 1; i <= n;i++)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		f node = f(b, c);
		mp[node]++;
	}
	map<f, ll>::iterator it;
	ll res= 0 ;
	for (it = mp.begin(); it != mp.end(); ++it)
	{
		res += it->second *  (n - it->second);
	}
	cout << res;

}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N (int)2e5+10
ll gcd(ll a, ll b)
{
	return b == 0 ? a : gcd(b, a % b);
}
struct f{
	int a, b;
	f(int q, int w)
	{
		int g = abs(gcd(q, w));
		if (g != 0)
		{
			a = q, b = w;
		}
		else
		{
			if (q == 0) a = 0, b = 1;
			else a = 1, b = 0;
		}
	}
	bool operator< (const f &c) const
	{
		if (a != c.a) return a < c.a;
		else return b < c.b;
	}
};
map<f, ll> mp;

int main(void)
{
	ll n;
	ll a, b;
	cin >> n >> a >> b;
	int i;
	for (i = 1; i <= n;i++)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		f node = f(b, c);
		mp[node]++;
	}
	map<f, ll>::iterator it;
	ll res= 0 ;
	for (it = mp.begin(); it != mp.end(); ++it)
	{
		res += it->second *  (n - it->second);
	}
	cout << res;

}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N (int)2e5+10
ll gcd(ll a, ll b)
{
	return b == 0 ? a : gcd(b, a % b);
}
struct f{
	int a, b;
	f(int q, int w)
	{
		int g = abs(gcd(q, w));
		if (g != 0)
		{
			a = q / g;
			b = w / g;
		}
		else
		{
			if (q == 0) a = 0, b = 1;
			else a = 1, b = 0;
		}
	}
	bool operator< (const f &c) const
	{
		if (a != c.a) return a < c.a;
		else return b < c.b;
	}
};
map<f, ll> mp;

int main(void)
{
	ll n;
	ll a, b;
	cin >> n >> a >> b;
	int i;
	for (i = 1; i <= n;i++)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		f node = f(b, c);
		mp[node]++;
	}
	map<f, ll>::iterator it;
	ll res= 0 ;
	for (it = mp.begin(); it != mp.end(); ++it)
	{
		res += it->second *  (n - it->second);
	}
	cout << res;

}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N (int)2e5+10
ll gcd(ll a, ll b)
{
	return b == 0 ? a : gcd(b, a % b);
}
ll a, b;
struct f{
	ll x, y;
	f(int q, int w){x = q, y = w;}
	bool operator< (const f &b) const
	{
		if (x != b.x) return x < b.x;
		else return y < b.y;
	 }
};
struct node{
	ll x, y;
	node(int q, int w){x = q, y = w;}
	bool operator< (const node &b) const
	{
		return y - a*x < b.y - b.x * a;
	}
};
map<node, ll> mp;
map<f, ll> p;
int main(void)
{
	ll n;

	cin >> n >> a >> b;
	int i;
	for (i = 1; i <= n;i++)
	{
		int q, w, e;
		scanf("%d%d%d", &q, &w, &e);
		f t = f(w, e);
		node temp = node(w, e);
		mp[temp]++, p[t]++;
	}
	map<node, ll>::iterator it;
	ll res= 0 ;
	for (it = mp.begin(); it != mp.end(); ++it)
	{
		res += (it->second - 1) * (it->second);
	}
	map<f, ll>::iterator it1;
	for (it1 = p.begin(); it1 != p.end(); ++it1)
	{
		res -= (it1->second - 1) * (it1->second);
	}
	cout << res;

}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<map>
#define ll long long
#define maxn 200010
#define eps 1e-12
#define inf 0x3f3f3f3f
inline ll read()
{
    ll x=0; char c=getchar(),f=1;
    for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
    for(;'0'<=c&&c<='9';c=getchar())x=x*10+c-'0';
    return x*f;
}
inline void write(ll x)
{
    static int buf[20],len; len=0;
    if(x<0)x=-x,putchar('-');
    for(;x;x/=10)buf[len++]=x%10;
    if(!len)putchar('0');
    else while(len)putchar(buf[--len]+'0');
}
inline void writeln(ll x){write(x); putchar('\n');}
inline void writesp(ll x){write(x); putchar(' ');}
std::map<ll,int>cnt1,cnt2;
int n,A,B;
int main()
{
// 	freopen("line.in","r",stdin);
// 	freopen("line.out","w",stdout);
	n=read(); A=read(); B=read();
	ll ans=0;
	for(int i=1;i<=n;i++){
		int x=read(),vx=read(),vy=read();
		ans+=cnt1[vy-(ll)A*vx]-cnt2[2000000000ll*vx+vy];
		++cnt1[vy-(ll)A*vx];
		++cnt2[2000000000ll*vx+vy];
	}
	writeln(ans*2);
// 	fclose(stdin); fclose(stdout);
	return 0;
}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<set>
#define ll long long
#define maxn 200010
#define eps 1e-12
#define inf 0x3f3f3f3f
inline ll read()
{
    ll x=0; char c=getchar(),f=1;
    for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
    for(;'0'<=c&&c<='9';c=getchar())x=x*10+c-'0';
    return x*f;
}
inline void write(ll x)
{
    static int buf[20],len; len=0;
    if(x<0)x=-x,putchar('-');
    for(;x;x/=10)buf[len++]=x%10;
    if(!len)putchar('0');
    else while(len)putchar(buf[--len]+'0');
}
inline void writeln(ll x){write(x); putchar('\n');}
inline void writesp(ll x){write(x); putchar(' ');}
struct point{
	int x;
	double va,vb;
}a[maxn];
int n,A,B;
bool cmp(point a,point b){return fabs(a.vb-b.vb)>eps?a.vb<b.vb:a.va<b.va;}
int main()
{
	// freopen("line.in","r",stdin);
	// freopen("line.out","w",stdout);
	n=read(); A=read(); B=read();
	for(int i=1;i<=n;i++){
		int x=read(),vx=read(),vy=read();
		a[i].x=x;
		double Sin=A/sqrt(1+(double)A*A),Cos=1/sqrt(1+(double)A*A);
		a[i].va=vx*Cos+vy*Sin; a[i].vb=vy*Cos-vx*Sin;
	}
	std::sort(a+1,a+n+1,cmp);
	int last=1;
	ll ans=0;
	for(int i=1;i<=n;i++)
		if(i==n||fabs(a[i].vb-a[i+1].vb)>eps){
			// printf("%d %d **********\n",last,i);
			int k=last;
			for(int j=last;j<=i;j++)
				if(j==i||fabs(a[j].va-a[j+1].va)>eps){
					// printf("%d %d\n",k,j);
					int cnt=j-k+1;
					ans+=(ll)cnt*(i-last+1-cnt);
					k=j+1;
				}
			last=i+1;
		}
	writeln(ans);
	fclose(stdin); fclose(stdout);
	return 0;
}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<map>
#define ll long long
#define maxn 200010
#define eps 1e-12
#define inf 0x3f3f3f3f
inline ll read()
{
    ll x=0; char c=getchar(),f=1;
    for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
    for(;'0'<=c&&c<='9';c=getchar())x=x*10+c-'0';
    return x*f;
}
inline void write(ll x)
{
    static int buf[20],len; len=0;
    if(x<0)x=-x,putchar('-');
    for(;x;x/=10)buf[len++]=x%10;
    if(!len)putchar('0');
    else while(len)putchar(buf[--len]+'0');
}
inline void writeln(ll x){write(x); putchar('\n');}
inline void writesp(ll x){write(x); putchar(' ');}
std::map<ll,int>cnt1,cnt2;
int n,A,B;
int main()
{
	freopen("line.in","r",stdin);
	freopen("line.out","w",stdout);
	n=read(); A=read(); B=read();
	ll ans=0;
	for(int i=1;i<=n;i++){
		int x=read(),vx=read(),vy=read();
		ans+=cnt1[vy-(ll)A*vx]-cnt2[2000000000ll*vx+vy];
		++cnt1[vy-(ll)A*vx];
		++cnt2[2000000000ll*vx+vy];
	}
	writeln(ans*2);
	fclose(stdin); fclose(stdout);
	return 0;
}


// 基本テンプレート

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <fstream>
#include <functional>
using namespace std;

#define rep(i,a,n) for(int (i)=(a); (i)<(n); (i)++)
#define repq(i,a,n) for(int (i)=(a); (i)<=(n); (i)++)
#define repr(i,a,n) for(int (i)=(a); (i)>=(n); (i)--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define int long long int

template<typename T> void chmax(T &a, T b) {a = max(a, b);}
template<typename T> void chmin(T &a, T b) {a = min(a, b);}
template<typename T> void chadd(T &a, T b) {a = a + b;}

typedef pair<int, int> pii;
typedef long long ll;

int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
const ll INF = 1001001001001001LL;
const ll MOD = 1000000007LL;

int cross(int xa, int ya, int xb, int yb) {
    return xa*yb - xb*ya;
}

int dot(int xa, int ya, int xb, int yb) {
    return xa*xb + ya*yb;
}

struct Elem {
    int X, P, Q;
    bool operator<(const Elem &e) const {
        return cross(P, Q, e.P, e.Q) < 0;
    }
};

signed main() {
    int N, A, B; scanf("%lld%lld%lld", &N, &A, &B);
    vector<Elem> lines;

    int cnt_parallel = 0, par_a = 0, par_b = 0;
    for(int i=0; i<N; i++) {
        int x, p, q; scanf("%lld%lld%lld", &x, &p, &q);
        if(p == 0 && q == 0) continue;

        // 元の？直線と平行
        if(cross(A, B, p, q) == 0) {
            cnt_parallel++;
            int D = dot(A, B, p, q);
            assert(D != 0);
            if(D > 0) par_a++;
            if(D < 0) par_b++;
        }
        else {
            lines.push_back(Elem{x, p, q});
        }
    }

    sort(lines.begin(), lines.end());
    int var_line = cnt_parallel, ans = par_a * par_b * 2;
    for(size_t i=0; i<lines.size(); i++) {
        if(i > 0) {
            Elem prev_line = lines[i-1];
            int xa = lines[i].P, ya = lines[i].Q;
            int xb = prev_line.P, yb = prev_line.Q;
            if(cross(xa, ya, xb, yb) != 0) {
                var_line++;
            }
        }
        ans += 2 * var_line;
    }
    printf("%lld\n", ans);
    return 0;
}


// 基本テンプレート

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <fstream>
#include <functional>
using namespace std;

#define rep(i,a,n) for(int (i)=(a); (i)<(n); (i)++)
#define repq(i,a,n) for(int (i)=(a); (i)<=(n); (i)++)
#define repr(i,a,n) for(int (i)=(a); (i)>=(n); (i)--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define int long long int

template<typename T> void chmax(T &a, T b) {a = max(a, b);}
template<typename T> void chmin(T &a, T b) {a = min(a, b);}
template<typename T> void chadd(T &a, T b) {a = a + b;}

typedef pair<int, int> pii;
typedef long long ll;

int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
const ll INF = 1001001001001001LL;
const ll MOD = 1000000007LL;

int cross(int xa, int ya, int xb, int yb) {
    return xa*yb - xb*ya;
}

int dot(int xa, int ya, int xb, int yb) {
    return xa*xb + ya*yb;
}

struct Elem {
    int X, P, Q;
};

pii get_vec(int x, int y) {
    if(x == 0) return make_pair(0, 1);
    if(y == 0) return make_pair(1, 0);

    // x は必ず正
    if(x < 0) x = -x, y = -y;
    int g = __gcd(x, y>0?y:-y);
    return make_pair(x/g, y/g);
}

int solve(vector<pii> lines) {
    map<int, int> mp;
    int M = lines.size(), ret = 0;
    for(auto e : lines) {
        mp[ e.first*e.first + e.second*e.second ]++;
    }
    for(auto e : lines) {
        int val = e.first*e.first + e.second*e.second;
        ret += M - mp[val];
    }
    // printf("solve: size = %zu, ans = %lld\n", lines.size(), ret);
    return ret;
}

signed main() {
    int N, A, B; scanf("%lld%lld%lld", &N, &A, &B);
    vector<Elem> lines;

    int no_move = 0;
    vector<pii> par_a, par_b;
    for(int i=0; i<N; i++) {
        int x, p, q; scanf("%lld%lld%lld", &x, &p, &q);

        // ただの点
        if(p == 0 && q == 0) {
            no_move++;
            continue;
        }

        // 元の？直線と平行
        if(cross(1, A, p, q) == 0) {
            int D = dot(1, A, p, q);
            assert(D != 0);
            if(D > 0) par_a.push_back(make_pair(p, q));
            if(D < 0) par_b.push_back(make_pair(p, q));
        }
        else {
            lines.push_back(Elem{x, p, q});
        }
    }

    vector<pii> deg_vec;
    map<pii, int> deg_set;
    for(auto e : lines) {
        pii deg = get_vec(e.P, e.Q);
        deg_vec.push_back(deg);
        deg_set[ deg ]++;
    }

    // printf("no_move = %lld, par_a = %lld, par_b = %lld\n", no_move, par_a, par_b);
    int ans = 0;
    ans += solve(par_a);
    ans += solve(par_b);
    ans += (par_a.size() * par_b.size() * 2);
    ans += (no_move * (par_a.size() + par_b.size()) * 2);
    int M = (int)lines.size() + par_a.size() + par_b.size();
    for(size_t i=0; i<lines.size(); i++) {
        pii deg = deg_vec[i];
        // printf("par_a = %lld, par_b = %lld, M = %lld, deg = %lld\n", par_a, par_b, M, deg_set[deg]);
        int intersect = M - deg_set[deg];
        ans += intersect;
    }
    printf("%lld\n", ans);
    return 0;
}


// 基本テンプレート

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <fstream>
#include <functional>
using namespace std;

#define rep(i,a,n) for(int (i)=(a); (i)<(n); (i)++)
#define repq(i,a,n) for(int (i)=(a); (i)<=(n); (i)++)
#define repr(i,a,n) for(int (i)=(a); (i)>=(n); (i)--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define int long long int

template<typename T> void chmax(T &a, T b) {a = max(a, b);}
template<typename T> void chmin(T &a, T b) {a = min(a, b);}
template<typename T> void chadd(T &a, T b) {a = a + b;}

typedef pair<int, int> pii;
typedef long long ll;

int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
const ll INF = 1001001001001001LL;
const ll MOD = 1000000007LL;

signed main() {
    int N, A, B; scanf("%lld%lld%lld", &N, &A, &B);

    int ans = 0;
    map< int, int > mp1;
    map< int, map<int, int> > mp2;
    for(int i=0; i<N; i++) {
        int X, P, Q; scanf("%lld%lld%lld", &X, &P, &Q);
        int val = Q - A*P;
        ans += 2*mp1[val] - 2*mp2[P][val];
        mp1[val]++; mp2[P][val]++;
    }
    printf("%lld\n", ans);
    return 0;
}


// 基本テンプレート

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <fstream>
#include <functional>
using namespace std;

#define rep(i,a,n) for(int (i)=(a); (i)<(n); (i)++)
#define repq(i,a,n) for(int (i)=(a); (i)<=(n); (i)++)
#define repr(i,a,n) for(int (i)=(a); (i)>=(n); (i)--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define int long long int

template<typename T> void chmax(T &a, T b) {a = max(a, b);}
template<typename T> void chmin(T &a, T b) {a = min(a, b);}
template<typename T> void chadd(T &a, T b) {a = a + b;}

typedef pair<int, int> pii;
typedef long long ll;

int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
const ll INF = 1001001001001001LL;
const ll MOD = 1000000007LL;

int cross(int xa, int ya, int xb, int yb) {
    return xa*yb - xb*ya;
}

int dot(int xa, int ya, int xb, int yb) {
    return xa*xb + ya*yb;
}

struct Elem {
    int X, P, Q;
    bool operator<(const Elem &e) const {
        return cross(P, Q, e.P, e.Q) < 0;
    }
};

signed main() {
    int N, A, B; scanf("%lld%lld%lld", &N, &A, &B);
    vector<Elem> lines;

    int cnt_parallel = 0, par_a = 0, par_b = 0, no_move = 0;
    for(int i=0; i<N; i++) {
        int x, p, q; scanf("%lld%lld%lld", &x, &p, &q);

        // ただの点
        if(p == 0 && q == 0) {
            no_move++;
            continue;
        }

        // 元の？直線と平行
        if(cross(1, A, p, q) == 0) {
            cnt_parallel++;
            int D = dot(1, A, p, q);
            assert(D != 0);
            if(D > 0) par_a++;
            if(D < 0) par_b++;
        }
        else {
            lines.push_back(Elem{x, p, q});
        }
    }

    sort(lines.begin(), lines.end());
    int var_line = cnt_parallel;
    // printf("no_move = %lld, par_a = %lld, par_b = %lld\n", no_move, par_a, par_b);
    int ans = (par_a * par_b * 2) + (no_move * (par_a + par_b) * 2);
    for(size_t i=0; i<lines.size(); i++) {
        if(i > 0) {
            Elem prev_line = lines[i-1];
            int xa = lines[i].P, ya = lines[i].Q;
            int xb = prev_line.P, yb = prev_line.Q;
            if(cross(xa, ya, xb, yb) != 0) {
                var_line++;
            }
        }
        ans += 2 * var_line;
    }
    printf("%lld\n", ans);
    return 0;
}