#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005, MAXM = 10005;
struct Chairman_tree {
  int n;
  struct Node {
    int value, cnt;
    Node *left, *right;
    inline void maintain() { value = left->value + right->value; }
  };
  Node *root[MAXM], pool[MAXN * 50], *alloc;
  vector<Node*> bin;
  Node* new_Node() {
    Node* ret;
    if (bin.empty())
      ret = alloc++;
    else {
      ret = bin.back();
      bin.pop_back();
    }
    ret->value = 0;
    ret->cnt = 1;
    ret->left = ret->right = NULL;
    return ret;
  }
  void build(int left, int right, Node*& curr) {
    curr = new_Node();
    if (left == right) return;
    int mid = (left + right) / 2;
    build(left, mid, curr->left);
    build(mid + 1, right, curr->right);
  }
  void init(int n, int m) {
    this->n = n;
    alloc = pool;
    bin.clear();
    build(1, m, root[0]);
    for (int i = 1; i <= n; i++) {
      root[i] = root[0];
      root[i]->cnt++;
    }
  }
  void recycle(Node* curr) {
    if (curr == NULL) return;
    if (--curr->cnt == 0) {
      recycle(curr->left);
      recycle(curr->right);
      bin.push_back(curr);
    }
  }
  void update(int pos, int value, int left, int right, Node*& curr,
              Node* last) {
    curr = new_Node();
    if (left == right) {
      curr->value = last->value + value;
      return;
    }
    int mid = (left + right) / 2;
    if (pos <= mid) {
      curr->right = last->right;
      curr->right->cnt++;
      update(pos, value, left, mid, curr->left, last->left);
    } else {
      curr->left = last->left;
      curr->left->cnt++;
      update(pos, value, mid + 1, right, curr->right, last->right);
    }
    curr->maintain();
  }
  int query(int l, int r, int left, int right, Node* curr, Node* last) {
    if (l == left && r == right) return curr->value - last->value;
    int mid = (left + right) / 2;
    if (r <= mid)
      return query(l, r, left, mid, curr->left, last->left);
    else if (l > mid)
      return query(l, r, mid + 1, right, curr->right, last->right);
    else
      return query(l, mid, left, mid, curr->left, last->left) +
             query(mid + 1, r, mid + 1, right, curr->right, last->right);
  }
};
Chairman_tree tree;
int n, k;
struct Record {
  int x, r, f;
  int left, right;
} rec[MAXN];
vector<int> scan;
inline int idx(int x) {
  return upper_bound(scan.begin(), scan.end(), x) - scan.begin();
}
int main() {
  scanf("%d%d", &n, &k);
  for (int i = 1; i <= n; i++) {
    scanf("%d%d%d", &rec[i].x, &rec[i].r, &rec[i].f);
    scan.push_back(rec[i].x - rec[i].r);
    scan.push_back(rec[i].x);
    scan.push_back(rec[i].x + rec[i].r);
  }
  sort(scan.begin(), scan.end());
  scan.resize(unique(scan.begin(), scan.end()) - scan.begin());
  sort(rec + 1, rec + n + 1,
       [](const Record& a, const Record& b) -> bool { return a.r > b.r; });
  for (int i = 1; i <= n; i++) {
    rec[i].left = idx(rec[i].x - rec[i].r);
    rec[i].right = idx(rec[i].x + rec[i].r);
    rec[i].x = idx(rec[i].x);
  }
  tree.init(10000, scan.size());
  long long ans = 0;
  for (int i = 1; i <= n; i++) {
    for (int j = max(1, rec[i].f - k); j <= min(10000, rec[i].f + k); j++)
      ans += tree.query(rec[i].left, rec[i].right, 1, scan.size(), tree.root[j],
                        tree.root[0]);
    Chairman_tree::Node* temp;
    tree.update(rec[i].x, 1, 1, scan.size(), temp, tree.root[rec[i].f]);
    tree.root[rec[i].f] = temp;
  }
  printf("%lld\n", ans);
  return 0;
}
