#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second

using namespace std;
typedef long long ll;
const int N = 2e4;

struct Treap{
    Treap *l, *r;
    int key, y, sz;

    Treap() : l(NULL), r(NULL), y(rand()), sz(1){}

    Treap(int x){
        l = r = NULL;
        key = x;
        y = rand();
        sz = 1;
    }
};

struct Node{
    int r, x, f;
    Node(){}
    Node(int r, int x, int f): r(r), x(x), f(f){}

    bool operator<(const Node & t) const
    {
        return r < t.r;
    }
};

vector <Treap *> root(N);

void recalc(Treap *t){
    if (t == NULL)
        return;
    t->sz = (t->l != NULL ? t->l->sz : 0) + 1 + (t->r != NULL ? t->r->sz : NULL);
}

pair <Treap *, Treap *> split(Treap *t, int x){
    if (t == NULL)
        return {NULL, NULL};
    if (t->key <= x){
        auto tmp = split(t->r, x);
        t->r = tmp.first;
        recalc(t);
        return {t, tmp.second};
    }
    else{
        auto tmp = split(t->l, x);
        t->l = tmp.second;
        recalc(t);
        return {tmp.first, t};
    }
}

Treap * merge(Treap *l, Treap *r){
    if (l == NULL)
        return r;
    if (r == NULL)
        return l;
    if (l->y >= r->y){
        l->l = merge(l->l, r);
        recalc(l);
        return l;
    }
    else{
        r->l = merge(l, r->l);
        recalc(r);
        return r;
    }
}

int getsize(Treap *t){
    if (t == NULL)
        return 0;
    return t->sz;
}

void insert(Treap * &t, int x){
    auto tmp = split(t, x);

    t = merge(merge(tmp.first, new Treap(x)), tmp.second);
}

void erase(Treap * &t, int x){
    auto tmp = split(t, x);
    auto tmp1 = split(t, x - 1);
    t = merge(tmp1.first, tmp.second);
}

int get(Treap * &t, int l, int r){
    auto tmp = split(t, r);
    auto tmp1 = split(tmp.first, l - 1);
    recalc(tmp1.second);
    int res = getsize(tmp1.second);

    t = merge(merge(tmp1.first, tmp1.second), tmp.second);

    return res;
}

int main()
{
    srand(time(NULL));

    int n, k;
    cin >> n >> k;

    ll ans = 0;

    vector <Node> p(n);

    for (int i = 0; i < n; i++){
        cin >> p[i].x >> p[i].r >> p[i].f;
        insert(root[p[i].f], p[i].x);
    }

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

    for (int i = 0; i < n; i++){
        erase(root[p[i].f], p[i].x);

        for (int j = p[i].f - k; j <= p[i].f + k; j++){
            if (j < 1 || j >= N)
                continue;
            ans += get(root[j], p[i].x - p[i].r, p[i].x + p[i].r);
        }
    }

    cout << ans;
}


// NA
#include <bits/stdc++.h>
#define BUFFER 5
#define BUFF(x) x + BUFFER
#define N_MAX (int) 1e5
#define X_MAX (int) 1e9
#define K_MAX 10
#define FREQ_MAX (int) (1e4 + 1e2)
#define NODES_MAX (int) (8 * N_MAX * log2(N_MAX))
// #pragma GCC optimize "O4"
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
typedef pair<int, int> pii;
int n, k;
struct S {
  int x, r, f, tree_pos;
  bool operator <(S other) { return r > other.r; }
} stations[BUFF(N_MAX)];
struct P {
  int idx, pos;
  bool operator <(P other) { return pos < other.pos; }
} positions[BUFF(N_MAX)];
ll bad_pairs;
struct N {
  int l, r, cnt;
  N() {}
  N(int l, int r, int cnt) : l(l), r(r), cnt(cnt) {}
} nodes[BUFF(NODES_MAX)];
int nodes_ptr;
int roots[BUFF(FREQ_MAX)];
int getMid(int l, int r) { return l + (r - l) / 2; }
int buildTree(int cur, int pos, int l, int r) {
  if (l <= pos && pos <= r) {
    if (!cur)
      cur = ++nodes_ptr;
    if (l == r)
      ++nodes[cur].cnt;
    else {
      int mid = getMid(l, r);
      int a = buildTree(nodes[cur].l, pos, l, mid);
      int b = buildTree(nodes[cur].r, pos, mid + 1, r);
      nodes[cur] = N(a, b, nodes[a].cnt + nodes[b].cnt);
    }
  }
  return cur;
}
int queryCount(int cur, int t_l, int t_r, int l, int r) {
  if (!cur || r < t_l || t_r < l)
    return 0;
  else if (t_l <= l && r <= t_r)
    return nodes[cur].cnt;
  else {
    int mid = getMid(l, r);
    int a = queryCount(nodes[cur].l, t_l, t_r, l, mid);
    int b = queryCount(nodes[cur].r, t_l, t_r, mid + 1, r);
    return a + b;
  }
}
int getLowerBound(int x) {
  // returns the first position[1..n] with x <= val
  if (x <= 0)
    return 1;
  int l, r, mid;
  l = 1, r = n;
  while (l <= r) {
    mid = getMid(l, r);
    if (x <= positions[mid].pos)
      r = mid - 1;
    else l = mid + 1;
  }
  return r + 1;
}
int getUpperBound(int x) {
  // returns the last position[1..n] with val <= x
  if (positions[n].pos <= x)
    return n;
  int l, r, mid;
  l = 1, r = n;
  while (l <= r) {
    mid = getMid(l, r);
    if (positions[mid].pos <= x)
      l = mid + 1;
    else r = mid - 1;
  }
  return l - 1;
}
void solve() {
  for (int i = 1, f_l, f_r, pos_l, pos_r; i <= n; ++i) {
    f_l = stations[i].f - k;
    f_r = stations[i].f + k;
    pos_l = getLowerBound(stations[i].x - stations[i].r);
    pos_r = getUpperBound(stations[i].x + stations[i].r);
    for (int j = max(1, f_l); j <= f_r; ++j)
      bad_pairs += queryCount(roots[j], pos_l, pos_r, 1, n);
    roots[stations[i].f] = buildTree(roots[stations[i].f], stations[i].tree_pos, 1, n);
  }
}
void program() {
  scanf("%d %d", &n, &k);
  for (int i = 1; i <= n; ++i) {
    scanf("%d %d %d", &stations[i].x, &stations[i].r, &stations[i].f);
    positions[i].idx = i;
    positions[i].pos = stations[i].x;
  }
  sort(positions + 1, positions + 1 + n);
  for (int i = 1; i <= n; ++i)
    stations[positions[i].idx].tree_pos = i;
  sort(stations + 1, stations + 1 + n);
  solve();
  printf("%lld\n", bad_pairs);
}
int main() {
#ifndef ONLINE_JUDGE
  freopen("input.txt", "r", stdin);
#endif
  program();
  return 0;
}


// AC Segment Tree, Input manipulation, Range query
#include <bits/stdc++.h>
#define BUFFER 5
#define BUFF(x) x + BUFFER
#define N_MAX (int) 1e5
#define FREQ_MAX (int) (1e4 + 1e2)
#define NODES_MAX (int) (8 * N_MAX * log2(N_MAX))
#pragma GCC optimize "O4"
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
typedef pair<int, int> pii;
int n, k;
struct S {
  int x, r, f, tree_pos;
  bool operator <(S other) { return r > other.r; }
} stations[BUFF(N_MAX)];
struct P {
  int idx, pos;
  bool operator <(P other) { return pos < other.pos; }
} positions[BUFF(N_MAX)];
ll bad_pairs;
struct N {
  int l, r, cnt;
  N() {}
  N(int l, int r, int cnt) : l(l), r(r), cnt(cnt) {}
} nodes[BUFF(NODES_MAX)];
int nodes_ptr;
int roots[BUFF(FREQ_MAX)];
int getMid(int l, int r) { return l + (r - l) / 2; }
int buildTree(int cur, int pos, int l, int r) {
  if (l <= pos && pos <= r) {
    if (!cur)
      cur = ++nodes_ptr;
    if (l == r)
      ++nodes[cur].cnt;
    else {
      int mid = getMid(l, r);
      int a = buildTree(nodes[cur].l, pos, l, mid);
      int b = buildTree(nodes[cur].r, pos, mid + 1, r);
      nodes[cur] = N(a, b, nodes[a].cnt + nodes[b].cnt);
    }
  }
  return cur;
}
int queryCount(int cur, int t_l, int t_r, int l, int r) {
  if (!cur || r < t_l || t_r < l)
    return 0;
  else if (t_l <= l && r <= t_r)
    return nodes[cur].cnt;
  else {
    int mid = getMid(l, r);
    int a = queryCount(nodes[cur].l, t_l, t_r, l, mid);
    int b = queryCount(nodes[cur].r, t_l, t_r, mid + 1, r);
    return a + b;
  }
}
int getLowerBound(int x) {
  // returns the first position[1..n] with x <= val
  if (x <= 0)
    return 1;
  int l, r, mid;
  l = 1, r = n;
  while (l <= r) {
    mid = getMid(l, r);
    if (x <= positions[mid].pos)
      r = mid - 1;
    else l = mid + 1;
  }
  return r + 1;
}
int getUpperBound(int x) {
  // returns the last position[1..n] with val <= x
  if (positions[n].pos <= x)
    return n;
  int l, r, mid;
  l = 1, r = n;
  while (l <= r) {
    mid = getMid(l, r);
    if (positions[mid].pos <= x)
      l = mid + 1;
    else r = mid - 1;
  }
  return l - 1;
}
void solve() {
  for (int i = 1, f_l, f_r, pos_l, pos_r; i <= n; ++i) {
    f_l = stations[i].f - k;
    f_r = stations[i].f + k;
    pos_l = getLowerBound(stations[i].x - stations[i].r);
    pos_r = getUpperBound(stations[i].x + stations[i].r);
    for (int j = max(1, f_l); j <= f_r; ++j)
      bad_pairs += queryCount(roots[j], pos_l, pos_r, 1, n);
    roots[stations[i].f] = buildTree(roots[stations[i].f], stations[i].tree_pos, 1, n);
  }
}
void program() {
  scanf("%d %d", &n, &k);
  for (int i = 1; i <= n; ++i) {
    scanf("%d %d %d", &stations[i].x, &stations[i].r, &stations[i].f);
    positions[i].idx = i;
    positions[i].pos = stations[i].x;
  }
  sort(positions + 1, positions + 1 + n);
  for (int i = 1; i <= n; ++i)
    stations[positions[i].idx].tree_pos = i;
  sort(stations + 1, stations + 1 + n);
  solve();
  printf("%lld\n", bad_pairs);
}
int main() {
#ifndef ONLINE_JUDGE
  freopen("input.txt", "r", stdin);
#endif
  program();
  return 0;
}


// NA
#include <bits/stdc++.h>
#define BUFFER 5
#define BUFF(x) x + BUFFER
#define N_MAX (int) 1e5
#define X_MAX (int) 1e9
#define K_MAX 10
#define FREQ_MAX (int) (1e4 + 1e2)
#define NODES_MAX (int) (8 * N_MAX * log2(N_MAX))
// #pragma GCC optimize "O4"
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
typedef pair<int, int> pii;
int n, k;
struct S {
  int x, r, f, tree_pos;
  bool operator <(S other) { return r > other.r; }
} stations[BUFF(N_MAX)];
struct P {
  int idx, pos;
  bool operator <(P other) { return pos < other.pos; }
} positions[BUFF(N_MAX)];
ll bad_pairs;
struct N {
  int l, r, cnt;
  N() {}
  N(int l, int r, int cnt) : l(l), r(r), cnt(cnt) {}
} nodes[BUFF(NODES_MAX)];
int nodes_ptr;
int roots[BUFF(FREQ_MAX)];
int getMid(int l, int r) { return l + (r - l) / 2; }
int buildTree(int cur, int pos, int l, int r) {
  if (l <= pos && pos <= r) {
    if (!cur)
      cur = ++nodes_ptr;
    if (l == r)
      ++nodes[cur].cnt;
    else {
      int mid = getMid(l, r);
      int a = buildTree(nodes[cur].l, pos, l, mid);
      int b = buildTree(nodes[cur].r, pos, mid + 1, r);
      nodes[cur] = N(a, b, nodes[a].cnt + nodes[b].cnt);
    }
  }
  return cur;
}
int queryCount(int cur, int t_l, int t_r, int l, int r) {
  if (!cur || r < t_l || t_r < l)
    return 0;
  else if (l <= t_l && t_r <= r)
    return nodes[cur].cnt;
  else {
    int mid = getMid(l, r);
    int a = queryCount(nodes[cur].l, t_l, t_r, l, mid);
    int b = queryCount(nodes[cur].r, t_l, t_r, mid + 1, r);
    return a + b;
  }
}
int getLowerBound(int x) {
  // returns the first position[1..n] with x <= val
  if (x <= 0)
    return 1;
  int l, r, mid;
  l = 1, r = n;
  while (l <= r) {
    mid = getMid(l, r);
    if (x <= positions[mid].pos)
      r = mid - 1;
    else l = mid + 1;
  }
  return r + 1;
}
int getUpperBound(int x) {
  // returns the last position[1..n] with val <= x
  if (positions[n].pos <= x)
    return n;
  int l, r, mid;
  l = 1, r = n;
  while (l <= r) {
    mid = getMid(l, r);
    if (positions[mid].pos <= x)
      l = mid + 1;
    else r = mid - 1;
  }
  return l - 1;
}
void solve() {
  for (int i = 1, f_l, f_r, pos_l, pos_r; i <= n; ++i) {
    f_l = max(1, stations[i].f - k);
    f_r = stations[i].f + k;
    pos_l = getLowerBound(stations[i].x - stations[i].r);
    pos_r = getUpperBound(stations[i].x + stations[i].r);
    for (int j = f_l; j <= f_r; ++j)
      bad_pairs += queryCount(roots[j], pos_l, pos_r, 1, n);
    roots[stations[i].f] = buildTree(roots[stations[i].f], stations[i].tree_pos, 1, n);
  }
}
void program() {
  scanf("%d %d", &n, &k);
  for (int i = 1; i <= n; ++i) {
    scanf("%d %d %d", &stations[i].x, &stations[i].r, &stations[i].f);
    positions[i].idx = i;
    positions[i].pos = stations[i].x;
  }
  sort(positions + 1, positions + 1 + n);
  for (int i = 1; i <= n; ++i)
    stations[positions[i].idx].tree_pos = i;
  sort(stations + 1, stations + 1 + n);
  solve();
  printf("%lld\n", bad_pairs);
}
int main() {
#ifndef ONLINE_JUDGE
  freopen("input.txt", "r", stdin);
#endif
  program();
  return 0;
}


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

struct dat {
   int x, r, f;
   bool operator<(dat d) const {
      return r < d.r;
   }
};

const int MX = 1e9;

int n, k;
dat dt[100 * 1000 + 10];
map<int,int> tree[100 * 100 + 10];

void upd(int cn, int i, int x) {
   while(i <= MX) {
      tree[cn][i] += x;
      i += i & (-i);
   }
}

int get(int cn, int i) {
   int rs = 0;
   while(i > 0) {
      rs += tree[cn][i];
      i -= i & (-i);
   }
   return rs;
}

int get(int cn, int l, int r) {
   if(r > MX) r = MX;
   if(l <= 0) return get(cn, r);
   if(l > r) return 0;
   return get(cn, r) - get(cn, l - 1);
}

int main() {
   scanf("%d%d", &n, &k);
   for(int i = 0; i < n; i++) {
      scanf("%d%d%d", &dt[i].x, &dt[i].r, &dt[i].f);
   }
   sort(dt, dt + n);
   for(int i = 0; i < n; i++) {
      for(int f = max(1, dt[i].f - k); f <= min(MX, dt[i].f + k); f++) {
         upd(f, dt[i].x, +1);
      }
   }
   long long rs = 0;
   for(int i = 0; i < n; i++) {
      for(int f = max(1, dt[i].f - k); f <= min(MX, dt[i].f + k); f++) {
         upd(f, dt[i].x, -1);
      }
      rs += get(dt[i].f, dt[i].x - dt[i].r, dt[i].x + dt[i].r);
   }
   printf("%lld\n", rs);
}


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

struct dat {
   int x, r, f;
   bool operator<(dat d) const {
      return r < d.r;
   }
};

const int MX = 1e9;

int n, k;
dat dt[100 * 1000 + 10];
map<int,int> tree[100 * 100 + 10];

void upd(int cn, int i, int x) {
   auto& mp = tree[cn];
   while(i <= MX) {
      mp[i] += x;
      i += i & (-i);
   }
}

int get(int cn, int i) {
   int rs = 0;
   auto& mp = tree[cn];
   while(i > 0) {
      auto it = mp.find(i);
      if(it != mp.end()) {
         rs += it->second;
      }
      i -= i & (-i);
   }
   return rs;
}

int get(int cn, int l, int r) {
   if(r > MX) r = MX;
   if(l <= 0) return get(cn, r);
   if(l > r) return 0;
   return get(cn, r) - get(cn, l - 1);
}

int main() {
   scanf("%d%d", &n, &k);
   for(int i = 0; i < n; i++) {
      scanf("%d%d%d", &dt[i].x, &dt[i].r, &dt[i].f);
   }
   sort(dt, dt + n);
   for(int i = 0; i < n; i++) {
      upd(dt[i].f, dt[i].x, +1);
   }
   long long rs = 0;
   for(int i = 0; i < n; i++) {
      upd(dt[i].f, dt[i].x, -1);
      for(int f = max(1, dt[i].f - k); f <= min(MX, dt[i].f + k); f++) {
         rs += get(f, dt[i].x - dt[i].r, dt[i].x + dt[i].r);
      }
   }
   printf("%lld\n", rs);
}


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

struct dat {
   int x, r, f;
   bool operator<(dat d) const {
      return r < d.r;
   }
};

const int MX = 1e9;

int n, k;
dat dt[100 * 1000 + 10];
unordered_map<int,map<int,int>> tree;

void upd(int cn, int i, int x) {
   auto& mp = tree[cn];
   while(i <= MX) {
      mp[i] += x;
      i += i & (-i);
   }
}

int get(int cn, int i) {
   int rs = 0;
   auto& mp = tree[cn];
   while(i > 0) {
      auto it = mp.find(i);
      if(it != mp.end()) {
         rs += it->second;
      }
      i -= i & (-i);
   }
   return rs;
}

int get(int cn, int l, int r) {
   if(r > MX) r = MX;
   if(l <= 0) return get(cn, r);
   if(l > r) return 0;
   return get(cn, r) - get(cn, l - 1);
}

int main() {
   scanf("%d%d", &n, &k);
   for(int i = 0; i < n; i++) {
      scanf("%d%d%d", &dt[i].x, &dt[i].r, &dt[i].f);
   }
   sort(dt, dt + n);
   for(int i = 0; i < n; i++) {
      upd(dt[i].f, dt[i].x, +1);
   }
   long long rs = 0;
   for(int i = 0; i < n; i++) {
      upd(dt[i].f, dt[i].x, -1);
      for(int f = max(1, dt[i].f - k); f <= min(MX, dt[i].f + k); f++) {
         rs += get(f, dt[i].x - dt[i].r, dt[i].x + dt[i].r);
      }
   }
   printf("%lld\n", rs);
}


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

struct dat {
   int x, r, f;
   bool operator<(dat d) const {
      return r < d.r;
   }
};

const int MX = 1e9;

int n, k;
dat dt[100 * 1000 + 10];
unordered_map<int,int> tree[100 * 100 + 10];

void upd(int cn, int i, int x) {
   auto& mp = tree[cn];
   while(i <= MX) {
      mp[i] += x;
      i += i & (-i);
   }
}

int get(int cn, int i) {
   int rs = 0;
   auto& mp = tree[cn];
   while(i > 0) {
      auto it = mp.find(i);
      if(it != mp.end()) {
         rs += it->second;
      }
      i -= i & (-i);
   }
   return rs;
}

int get(int cn, int l, int r) {
   if(r > MX) r = MX;
   if(l <= 0) return get(cn, r);
   if(l > r) return 0;
   return get(cn, r) - get(cn, l - 1);
}

int main() {
   scanf("%d%d", &n, &k);
   for(int i = 0; i < n; i++) {
      scanf("%d%d%d", &dt[i].x, &dt[i].r, &dt[i].f);
   }
   sort(dt, dt + n);
   for(int i = 0; i < n; i++) {
      upd(dt[i].f, dt[i].x, +1);
   }
   long long rs = 0;
   for(int i = 0; i < n; i++) {
      upd(dt[i].f, dt[i].x, -1);
      for(int f = max(1, dt[i].f - k); f <= min(MX, dt[i].f + k); f++) {
         rs += get(f, dt[i].x - dt[i].r, dt[i].x + dt[i].r);
      }
   }
   printf("%lld\n", rs);
}


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

struct dat {
   int x, r, f;
   bool operator<(dat d) const {
      return r < d.r;
   }
};

struct Tree {
   Tree *L, *R; int val;
   Tree() {
      L = R = 0; val = 0;
   }
};

const int MX = 1e9;

int n, k;
dat dt[100 * 1000 + 10];
Tree* tree[100 * 100 + 10];

void upd(Tree *cn, int b, int e, int i, int x) {
   if(i <= b && e <= i) {
      cn->val += x;
      return;
   }
   if(i < b || i > e) return;
   if(!cn->L) cn->L = new Tree();
   if(!cn->R) cn->R = new Tree();
   int m = (b + e) / 2;
   upd(cn->L, b, m, i, x);
   upd(cn->R, m+1, e, i, x);
   cn->val = cn->L->val + cn->R->val;
}

int get(Tree* cn, int b, int e, int l, int r) {
   if(!cn) return 0;
   if(l <= b && e <= r) return cn->val;
   if(r < b || l > e) return 0;
   int m = (b + e) / 2;
   return get(cn->L, b, m, l, r) + get(cn->R, m+1, e, l, r);
}

void upd(int cn, int i, int x) {
   if(!tree[cn]) tree[cn] = new Tree();
   upd(tree[cn], 1, MX, i, x);
}

int get(int cn, int l, int r) {
   if(r > MX) r = MX;
   if(l <= 0) l = 1;
   return get(tree[cn], 1, MX, l, r);
}

int main() {
   scanf("%d%d", &n, &k);
   for(int i = 0; i < n; i++) {
      scanf("%d%d%d", &dt[i].x, &dt[i].r, &dt[i].f);
   }
   sort(dt, dt + n);
   for(int i = 0; i < n; i++) {
      upd(dt[i].f, dt[i].x, +1);
   }
   long long rs = 0;
   for(int i = 0; i < n; i++) {
      upd(dt[i].f, dt[i].x, -1);
      for(int f = max(1, dt[i].f - k); f <= min(MX, dt[i].f + k); f++) {
         rs += get(f, dt[i].x - dt[i].r, dt[i].x + dt[i].r);
      }
   }
   printf("%lld\n", rs);
}


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

struct dat {
   int x, r, f;
   bool operator<(dat d) const {
      return r < d.r;
   }
};

const int MX = 1e9;

int n, k;
dat dt[100 * 1000 + 10];
unordered_map<int,map<int,int>> tree;

void upd(int cn, int i, int x) {
   auto& mp = tree[cn];
   while(i <= MX) {
      mp[i] += x;
      i += i & (-i);
   }
}

int get(int cn, int i) {
   int rs = 0;
   auto& mp = tree[cn];
   while(i > 0) {
      auto it = mp.find(i);
      if(it != mp.end()) {
         rs += it->second;
      }
      i -= i & (-i);
   }
   return rs;
}

int get(int cn, int l, int r) {
   if(r > MX) r = MX;
   if(l <= 0) return get(cn, r);
   if(l > r) return 0;
   return get(cn, r) - get(cn, l - 1);
}

int main() {
   scanf("%d%d", &n, &k);
   for(int i = 0; i < n; i++) {
      scanf("%d%d%d", &dt[i].x, &dt[i].r, &dt[i].f);
   }
   sort(dt, dt + n);
   for(int i = 0; i < n; i++) {
      for(int f = max(1, dt[i].f - k); f <= min(MX, dt[i].f + k); f++) {
         upd(f, dt[i].x, +1);
      }
   }
   long long rs = 0;
   for(int i = 0; i < n; i++) {
      for(int f = max(1, dt[i].f - k); f <= min(MX, dt[i].f + k); f++) {
         upd(f, dt[i].x, -1);
      }
      rs += get(dt[i].f, dt[i].x - dt[i].r, dt[i].x + dt[i].r);
   }
   printf("%lld\n", rs);
}


// https://codeforces.com/contest/762/problem/E

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;

struct Station {
    int x, r, f;
    bool operator<(const Station& other){
        return r < other.r;
    }
};

const int MAX_F = 1e4 + 11;
const int MAX_N = 1e5;
int N, K;
vector<Station> stations;
vector<set<int>> pos_set_by_freq;

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

    cin >> N >> K;

    stations.assign(N, Station());
    for (int i = 0; i < N; ++i) {
        int x, r, f;
        cin >> x >> r >> f;
        stations[i] = Station { x, r, f };
    }

    sort(stations.begin(), stations.end());
    reverse(stations.begin(), stations.end());

    pos_set_by_freq.assign(MAX_F, set<int>());

    long long ans = 0;
    for (int i = 0; i < N; ++i) {
        auto station = stations[i];
        for (int df = -K; df <= K; ++df) {
            int f = station.f + df;
            if (f <= 0) continue;
            int l = station.x - station.r;
            int r = station.x + station.r;
            auto itl = pos_set_by_freq[f].lower_bound(l);
            auto itr = pos_set_by_freq[f].upper_bound(r);
            int il = distance(pos_set_by_freq[f].begin(), itl);
            int ir = distance(pos_set_by_freq[f].begin(), itr);
            ans += ir - il;
        }
        pos_set_by_freq[station.f].insert(station.x);
    }
    cout << ans << endl;

    return 0;
}


// https://codeforces.com/contest/762/problem/E

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;

struct Station {
    int x, r, f;
    bool operator<(const Station& other){
        return r < other.r;
    }
};

const int MAX_F = 1e4 + 11;
const int MAX_N = 1e5;
int N, K;
vector<Station> stations;
vector<set<int>> pos_set_by_freq;

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

    cin >> N >> K;

    stations.assign(N, Station());
    for (int i = 0; i < N; ++i) {
        int x, r, f;
        cin >> x >> r >> f;
        stations[i] = Station { x, r, f };
    }

    sort(stations.begin(), stations.end());
    reverse(stations.begin(), stations.end());

    pos_set_by_freq.assign(MAX_F, set<int>());

    long long ans = 0;
    for (int i = 0; i < N; ++i) {
        auto station = stations[i];
        for (int df = -K; df <= K; ++df) {
            int f = station.f + df;
            if (f <= 0) continue;
            int l = station.x - station.r;
            int r = station.x + station.r;
            auto itl = lower_bound(pos_set_by_freq[f].begin(), pos_set_by_freq[f].end(), l);
            auto itr = upper_bound(pos_set_by_freq[f].begin(), pos_set_by_freq[f].end(), r);
            int il = distance(pos_set_by_freq[f].begin(), itl);
            int ir = distance(pos_set_by_freq[f].begin(), itr);
            ans += ir - il;
        }
        pos_set_by_freq[station.f].insert(station.x);
    }
    cout << ans << endl;

    return 0;
}


// https://codeforces.com/contest/762/problem/E

#include <iostream>
#include <random>
#include <vector>
#include <algorithm>

using namespace std;

class Treap {
protected:
    struct Node {
        int key;
        int count;
        int priority;
        Node *left, *right;
        Node(int key, int priority)
            : key(key)
            , count(1)
            , priority(priority)
            , left(nullptr)
            , right(nullptr)
            {
                // Do nothing
            }
    };
    using Tree = Node*;

    std::mt19937 random;
    Tree root = nullptr;

public:
    // O(logN)
    void insert(int key) {
        insert(root, new Node(key, random()));
    }
    // O(logN)
    long long count(int l, int r) {
        return count(root, l, r);
    }

protected:
    long long count(Tree tree) {
        return tree ? tree->count : 0;
    }
    void pushup(Tree tree) {
        if (tree) {
            tree->count = 1 + count(tree->left) + count(tree->right);
        }
    }
    void pushdown(Tree tree) {
        pushup(tree);
    }
    // O(logN)
    // left: <= key, right: > key
    void split(Tree tree, int key, Tree& left, Tree& right) {
        if (!tree) {
            left = right = nullptr;
            return;
        }
        pushdown(tree);
        if (key < tree->key) {
            split(tree->left, key, left, tree->left);
            right = tree;
        } else {
            split(tree->right, key, tree->right, right);
            left = tree;
        }
        pushup(tree);
    }
    // O(logN)
    void merge(Tree &tree, Tree left, Tree right) {
        pushdown(left);
        pushdown(right);
        if (!left || !right) {
            tree = left ? left : right;
        } else if (left->priority > right->priority) {
            merge(left->right, left->right, right);
            tree = left;
        } else {
            merge(right->left, left, right->left);
            tree = right;
        }
        pushup(tree);
    }
    // O(logN)
    void insert(Tree &tree, Tree item) {
        if (!tree) {
            tree = item;
            return;
        }
        pushdown(tree);
        if (item->priority > tree->priority) {
            split(tree, item->key, item->left, item->right);
            tree = item;
        } else {
            insert(item->key < tree->key ? tree->left : tree->right, item);
        }
        pushup(tree);
    }
    // O(logN)
    // count elements where key = [l, r)
    long long count(Tree &tree, int l, int r) {
        Tree t1, t2, t3;
        long long ans;
        split(tree, l - 1, t1, t2);
        split(t2, r - 1, t2, t3);
        ans = count(t2);
        merge(t2, t2, t3);
        merge(tree, t1, t2);
        return ans;
    }
};

struct Station {
    int x, r, f;
    bool operator<(const Station& other){
        return r < other.r;
    }
};

const int MAX_F = 1e4 + 11;
int N, K;
vector<Station> stations;
vector<Treap> treap_by_freq(MAX_F);

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

    cin >> N >> K;
    stations.assign(N, Station());
    for (int i = 0; i < N; ++i) {
        int x, r, f;
        cin >> x >> r >> f;
        stations[i] = Station { x, r, f };
    }

    sort(stations.begin(), stations.end());
    reverse(stations.begin(), stations.end());

    long long ans = 0;
    for (int i = 0; i < N; ++i) {
        auto station = stations[i];
        for (int df = -K; df <= K; ++df) {
            int f = station.f + df;
            if (f <= 0) continue;
            int l = station.x - station.r;
            int r = station.x + station.r;
            ans += treap_by_freq[f].count(l, r+1);
        }
        treap_by_freq[station.f].insert(station.x);
    }
    cout << ans << endl;

    return 0;
}


// https://codeforces.com/contest/762/problem/E

#include <iostream>
#include <cmath>
#include <random>
#include <vector>
#include <algorithm>

using namespace std;

class Treap {
protected:
    struct Node {
        int key;
        int count;
        int priority;
        Node *left, *right;
        Node(int key, int priority)
            : key(key)
            , count(1)
            , priority(priority)
            , left(nullptr)
            , right(nullptr)
            {
                // Do nothing
            }
    };
    using Tree = Node*;

    std::random_device random;
    Tree root = nullptr;

public:
    // O(logN)
    void insert(int key) {
        insert(root, new Node(key, random()));
    }
    // O(logN)
    long long count(int l, int r) {
        return count(root, l, r);
    }

protected:
    long long count(Tree tree) {
        return tree ? tree->count : 0;
    }
    virtual void pushup(Tree tree) {
        if (tree) {
            tree->count = 1 + count(tree->left) + count(tree->right);
        }
    }
    virtual void pushdown(Tree tree) {
        pushup(tree);
    }
    // O(logN)
    // left: <= key, right: > key
    void split(Tree tree, int key, Tree& left, Tree& right) {
        if (!tree) {
            left = right = nullptr;
            return;
        }
        pushdown(tree);
        if (key < tree->key) {
            split(tree->left, key, left, tree->left);
            right = tree;
        } else {
            split(tree->right, key, tree->right, right);
            left = tree;
        }
        pushup(tree);
    }
    // O(logN)
    void merge(Tree &tree, Tree left, Tree right) {
        pushdown(left);
        pushdown(right);
        if (!left || !right) {
            tree = left ? left : right;
        } else if (left->priority > right->priority) {
            merge(left->right, left->right, right);
            tree = left;
        } else {
            merge(right->left, left, right->left);
            tree = right;
        }
        pushup(tree);
    }
    // O(logN)
    void insert(Tree &tree, Tree item) {
        if (!tree) {
            tree = item;
            return;
        }
        pushdown(tree);
        if (item->priority > tree->priority) {
            split(tree, item->key, item->left, item->right);
            tree = item;
        } else {
            insert(item->key < tree->key ? tree->left : tree->right, item);
        }
        pushup(tree);
    }
    // O(logN)
    // count elements where key = [l, r)
    long long count(Tree &tree, int l, int r) {
        Tree t1, t2, t3;
        long long ans;
        split(tree, l - 1, t1, t2);
        split(t2, r - 1, t2, t3);
        ans = count(t2);
        merge(t2, t2, t3);
        merge(tree, t1, t2);
        return ans;
    }
};

struct Station {
    int x, r, f;
    bool operator<(const Station& other){
        return r < other.r;
    }
};

const int MAX_F = 1e4 + 11;
const int MAX_N = 1e5;
int N, K;
vector<Station> stations;
vector<Treap*> treap_by_freq;

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

    cin >> N >> K;

    stations.assign(N, Station());
    for (int i = 0; i < N; ++i) {
        int x, r, f;
        cin >> x >> r >> f;
        stations[i] = Station { x, r, f };
    }

    sort(stations.begin(), stations.end());
    reverse(stations.begin(), stations.end());

    treap_by_freq.assign(MAX_F, nullptr);
    for (int i = 0; i < MAX_F; ++i) {
        treap_by_freq[i] = new Treap();
    }

    long long ans = 0;
    for (int i = 0; i < N; ++i) {
        auto station = stations[i];
        for (int df = -K; df <= K; ++df) {
            int f = station.f + df;
            if (f <= 0) continue;
            int l = station.x - station.r;
            int r = station.x + station.r;
            ans += treap_by_freq[f]->count(l, r+1);
        }
        treap_by_freq[station.f]->insert(station.x);
    }
    cout << ans << endl;

    return 0;
}


// https://codeforces.com/contest/762/problem/E

#include <iostream>
#include <cmath>
#include <random>
#include <vector>
#include <algorithm>

using namespace std;

class Treap {
protected:
    struct Node {
        int key;
        int count;
        int priority;
        Node *left, *right;
        Node(int key, int priority)
            : key(key)
            , count(1)
            , priority(priority)
            , left(nullptr)
            , right(nullptr)
            {
                // Do nothing
            }
    };
    using Tree = Node*;

    std::random_device random;
    Tree root = nullptr;

public:
    // O(logN)
    void insert(int key) {
        insert(root, new Node(key, random()));
    }
    // O(logN)
    long long count(int l, int r) {
        return count(root, l, r);
    }

protected:
    long long count(Tree tree) {
        return tree ? tree->count : 0;
    }
    virtual void pushup(Tree tree) {
        if (tree) {
            tree->count = 1 + count(tree->left) + count(tree->right);
        }
    }
    virtual void pushdown(Tree tree) {
        pushup(tree);
    }
    // O(logN)
    // left: <= key, right: > key
    void split(Tree tree, int key, Tree& left, Tree& right) {
        if (!tree) {
            left = right = nullptr;
            return;
        }
        pushdown(tree);
        if (key < tree->key) {
            split(tree->left, key, left, tree->left);
            right = tree;
        } else {
            split(tree->right, key, tree->right, right);
            left = tree;
        }
        pushup(tree);
    }
    // O(logN)
    void merge(Tree &tree, Tree left, Tree right) {
        pushdown(left);
        pushdown(right);
        if (!left || !right) {
            tree = left ? left : right;
        } else if (left->priority > right->priority) {
            merge(left->right, left->right, right);
            tree = left;
        } else {
            merge(right->left, left, right->left);
            tree = right;
        }
        pushup(tree);
    }
    // O(logN)
    void insert(Tree &tree, Tree item) {
        if (!tree) {
            tree = item;
            return;
        }
        pushdown(tree);
        if (item->priority > tree->priority) {
            split(tree, item->key, item->left, item->right);
            tree = item;
        } else {
            insert(item->key < tree->key ? tree->left : tree->right, item);
        }
        pushup(tree);
    }
    // O(logN)
    // count elements where key = [l, r)
    long long count(Tree &tree, int l, int r) {
        Tree t1, t2, t3;
        long long ans;
        split(tree, l - 1, t1, t2);
        split(t2, r - 1, t2, t3);
        ans = count(t2);
        merge(t2, t2, t3);
        merge(tree, t1, t2);
        return ans;
    }
};

struct Station {
    int x, r, f;
    bool operator<(const Station& other){
        return r < other.r;
    }
};

const int MAX_F = 1e4 + 10;
const int MAX_N = 1e5 + 10;
int N, K;
vector<Station> stations;
vector<Treap*> treap_by_freq;

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

    cin >> N >> K;

    stations.assign(N, Station());
    for (int i = 0; i < N; ++i) {
        int x, r, f;
        cin >> x >> r >> f;
        stations[i] = Station { x, r, f };
    }

    sort(stations.begin(), stations.end());
    reverse(stations.begin(), stations.end());

    treap_by_freq.assign(MAX_F, nullptr);
    for (int i = 0; i < MAX_F; ++i) {
        treap_by_freq[i] = new Treap();
    }

    long long ans = 0;
    for (int i = 0; i < N; ++i) {
        auto station = stations[i];
        for (int df = -K; df <= K; ++df) {
            int f = station.f + df;
            if (f <= 0) continue;
            int l = station.x - station.r;
            int r = station.x + station.r;
            ans += treap_by_freq[f]->count(l, r+1);
        }
        treap_by_freq[station.f]->insert(station.x);
    }
    cout << ans << endl;

    return 0;
}


#include <cinttypes>
#include <inttypes.h>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <map>
#include <utility>
#include <cmath>
#include <algorithm>
#include <set>
#include <stack>
#include <list>
#include <bitset>
#include <functional>

#define vi vector<int>
#define vvi vector<vi>
#define pii pair<int,int>
#define vpii vector<pii>
#define ll long long

#define all(s) s.begin(), s.end()

using namespace std;

int nxi() { int a; cin >> a; return a; }

vector<int> dsu;

int dsu_get(int v) {
	return (v == dsu[v])
		? v
		: (dsu[v] = dsu_get(dsu[v]));
}

void dsu_join(int a, int b) {
	a = dsu_get(a);
	b = dsu_get(b);
	if (rand() & 1)
		swap(a, b);

	if (a != b)
		dsu[a] = b;
}

vector<long long> a;
void inc(int i, int v) {
	for (; i < a.size(); i |= i + 1) {
		a[i] += v;
	}
}

long long get(int r) {
	long long ans = 0;
	for (; r >= 0; r = (r & (r + 1)) - 1) {
		ans += a[r];
	}
	return ans;
}

long long get(int l, int r) {
	return get(r) - get(l - 1);
}

struct s_station {
	int x, r, f;

	bool operator< (const s_station & s2) {
		return x < s2.x;
	}
};

bool operator< (const s_station & s1, const s_station & s2) {
	return s1.x < s2.x;
}

int main() {

#ifdef _DEBUG
	freopen("data.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif

	int n = nxi(), k = nxi();

	vector<s_station> a(n);
	for (auto & s : a) {
		scanf("%d%d%d", &s.x, &s.r, &s.f);
	}

	sort(all(a));

	vector<vector<s_station>> fth(10011);
	vector<vector<vector<int>>> tr(10011);

	for (auto & t : a) {
		fth[t.f].push_back(t);
	}

	for (int i = 0; i < 10000; ++i) {
		int len = fth[i].size();

		if (!len) continue;

		tr[i].assign(len * 4, vi());

		const std::function<void (const int, const int, const int)> build = [&](const int ind, const int l, const int r) {
			if (l == r) {
				tr[i][ind].push_back(fth[i][l].x - fth[i][l].r);
				return;
			}

			int m = (l + r) / 2;
			build(2 * ind, l, m);
			build(2 * ind + 1, m + 1, r);

			int l1 = tr[i][2 * ind].size(), l2 = tr[i][2 * ind + 1].size();
			int j1 = 0, j2 = 0;
			for (int j = 0; j < l1 + l2; ++j) {
				if (j1 < l1 && (j2 == l2 || tr[i][2 * ind][j1] < tr[i][2 * ind + 1][j2])) {
					tr[i][ind].push_back(tr[i][2 * ind][j1]);
					++j1;
				}
				else {
					tr[i][ind].push_back(tr[i][2 * ind + 1][j2]);
					++j2;
				}
			}
		};

		build(1, 0, len - 1);
	}

	const std::function<int(const int, const int, const int, const int, const int, const int, const int)> find =
		[&](const int fq, const int ind, const int lt, const int rt, const int l, const int r, const int x) -> int
	{
		if (r < l) return 0;

		if (l == lt && r == rt) {
			auto it = upper_bound(all(tr[fq][ind]), x);
			return (it - tr[fq][ind].begin());
		}

		int m = (lt + rt) / 2;
		int res1 = find(fq, 2 * ind, lt, m, l, min(m, r), x);
		int res2 = find(fq, 2 * ind + 1, m + 1, rt, max(l, m + 1), r, x);

		return res1 + res2;
	};

	ll ans = 0;
	for (int i = 0; i <= 10000; ++i) {
		int len = fth[i].size();
		if (!len) continue;

		for (int fq = max(1, i - k); fq <= i + k; ++fq) {
			if (fth[fq].empty()) continue;

			for (int j = 0; j < len; ++j) {
				s_station s(fth[i][j]);
				auto it1 = upper_bound(all(fth[fq]), s);
				s.x += fth[i][j].r;
				auto it2 = lower_bound(all(fth[fq]), s);
				if (it2 == fth[fq].end()) --it2;

				if (it1 == fth[fq].end() || it2 < it1 || it2->x > s.x) continue;

				int res = find(fq, 1, 0, fth[fq].size() - 1, it1 - fth[fq].begin(), it2 - fth[fq].begin(), fth[i][j].x);

				ans += res;
			}
		}
	}

	cout << ans;

	return 0;
}


#include <cinttypes>
#include <inttypes.h>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <map>
#include <utility>
#include <cmath>
#include <algorithm>
#include <set>
#include <stack>
#include <list>
#include <bitset>
#include <functional>

#define vi vector<int>
#define vvi vector<vi>
#define pii pair<int,int>
#define vpii vector<pii>
#define ll long long

#define all(s) s.begin(), s.end()

using namespace std;

int nxi() { int a; cin >> a; return a; }

vector<int> dsu;

int dsu_get(int v) {
	return (v == dsu[v])
		? v
		: (dsu[v] = dsu_get(dsu[v]));
}

void dsu_join(int a, int b) {
	a = dsu_get(a);
	b = dsu_get(b);
	if (rand() & 1)
		swap(a, b);

	if (a != b)
		dsu[a] = b;
}

vector<long long> a;
void inc(int i, int v) {
	for (; i < a.size(); i |= i + 1) {
		a[i] += v;
	}
}

long long get(int r) {
	long long ans = 0;
	for (; r >= 0; r = (r & (r + 1)) - 1) {
		ans += a[r];
	}
	return ans;
}

long long get(int l, int r) {
	return get(r) - get(l - 1);
}

struct s_station {
	int x, r, f;

	bool operator< (const s_station & s2) {
		return x < s2.x;
	}
};

bool operator< (const s_station & s1, const s_station & s2) {
	return s1.x < s2.x;
}

int main() {

#ifdef _DEBUG
	freopen("data.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif

	int n = nxi(), k = nxi();

	vector<s_station> a(n);
	for (auto & s : a) {
		scanf("%d%d%d", &s.x, &s.r, &s.f);
	}

	sort(all(a));

	vector<vector<s_station>> fth(10011);
	vector<vector<vector<int>>> tr(10011);

	for (auto & t : a) {
		fth[t.f].push_back(t);
	}

	for (int i = 0; i <= 10000; ++i) {
		int len = fth[i].size();

		if (!len) continue;

		tr[i].assign(len * 4, vi());

		const std::function<void (const int, const int, const int)> build = [&](const int ind, const int l, const int r) {
			if (l == r) {
				tr[i][ind].push_back(fth[i][l].x - fth[i][l].r);
				return;
			}

			int m = (l + r) / 2;
			build(2 * ind, l, m);
			build(2 * ind + 1, m + 1, r);

			int l1 = tr[i][2 * ind].size(), l2 = tr[i][2 * ind + 1].size();
			int j1 = 0, j2 = 0;
			for (int j = 0; j < l1 + l2; ++j) {
				if (j1 < l1 && (j2 == l2 || tr[i][2 * ind][j1] < tr[i][2 * ind + 1][j2])) {
					tr[i][ind].push_back(tr[i][2 * ind][j1]);
					++j1;
				}
				else {
					tr[i][ind].push_back(tr[i][2 * ind + 1][j2]);
					++j2;
				}
			}
		};

		build(1, 0, len - 1);
	}

	const std::function<int(const int, const int, const int, const int, const int, const int, const int)> find =
		[&](const int fq, const int ind, const int lt, const int rt, const int l, const int r, const int x) -> int
	{
		if (r < l) return 0;

		if (l == lt && r == rt) {
			auto it = upper_bound(all(tr[fq][ind]), x);
			return (it - tr[fq][ind].begin());
		}

		int m = (lt + rt) / 2;
		int res1 = find(fq, 2 * ind, lt, m, l, min(m, r), x);
		int res2 = find(fq, 2 * ind + 1, m + 1, rt, max(l, m + 1), r, x);

		return res1 + res2;
	};

	ll ans = 0;
	for (int i = 0; i <= 10000; ++i) {
		int len = fth[i].size();
		if (!len) continue;

		for (int fq = max(1, i - k); fq <= i + k; ++fq) {
			if (fth[fq].empty()) continue;

			for (int j = 0; j < len; ++j) {
				s_station s(fth[i][j]);
				auto it1 = upper_bound(all(fth[fq]), s);
				s.x += fth[i][j].r;
				auto it2 = lower_bound(all(fth[fq]), s);
				if (it2 == fth[fq].end()) --it2;
				if (it2 > fth[fq].begin() && it2->x > s.x) --it2;

				if (it1 == fth[fq].end() || it2 < it1 || it2->x > s.x) continue;

				int res = find(fq, 1, 0, fth[fq].size() - 1, it1 - fth[fq].begin(), it2 - fth[fq].begin(), fth[i][j].x);

				ans += res;
			}
		}
	}

	cout << ans;

	return 0;
}


#include <cinttypes>
#include <inttypes.h>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <map>
#include <utility>
#include <cmath>
#include <algorithm>
#include <set>
#include <stack>
#include <list>
#include <bitset>
#include <functional>

#define vi vector<int>
#define vvi vector<vi>
#define pii pair<int,int>
#define vpii vector<pii>
#define ll long long

#define all(s) s.begin(), s.end()

using namespace std;

int nxi() { int a; cin >> a; return a; }

vector<int> dsu;

int dsu_get(int v) {
	return (v == dsu[v])
		? v
		: (dsu[v] = dsu_get(dsu[v]));
}

void dsu_join(int a, int b) {
	a = dsu_get(a);
	b = dsu_get(b);
	if (rand() & 1)
		swap(a, b);

	if (a != b)
		dsu[a] = b;
}

vector<long long> a;
void inc(int i, int v) {
	for (; i < a.size(); i |= i + 1) {
		a[i] += v;
	}
}

long long get(int r) {
	long long ans = 0;
	for (; r >= 0; r = (r & (r + 1)) - 1) {
		ans += a[r];
	}
	return ans;
}

long long get(int l, int r) {
	return get(r) - get(l - 1);
}

struct s_station {
	int x, r, f;

	bool operator< (const s_station & s2) {
		return x < s2.x;
	}
};

bool operator< (const s_station & s1, const s_station & s2) {
	return s1.x < s2.x;
}

int main() {

#ifdef _DEBUG
	freopen("data.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif

	int n = nxi(), k = nxi();

	vector<s_station> a(n);
	for (auto & s : a) {
		scanf("%d%d%d", &s.x, &s.r, &s.f);
	}

	sort(all(a));

	vector<vector<s_station>> fth(10011);
	vector<vector<vector<int>>> tr(10011);

	for (auto & t : a) {
		fth[t.f].push_back(t);
	}

	for (int i = 0; i < 10000; ++i) {
		int len = fth[i].size();

		if (!len) continue;

		tr[i].assign(len * 4, vi());

		const std::function<void (const int, const int, const int)> build = [&](const int ind, const int l, const int r) {
			if (l == r) {
				tr[i][ind].push_back(fth[i][l].x - fth[i][l].r);
				return;
			}

			int m = (l + r) / 2;
			build(2 * ind, l, m);
			build(2 * ind + 1, m + 1, r);

			int l1 = tr[i][2 * ind].size(), l2 = tr[i][2 * ind + 1].size();
			int j1 = 0, j2 = 0;
			for (int j = 0; j < l1 + l2; ++j) {
				if (j1 < l1 && (j2 == l2 || tr[i][2 * ind][j1] < tr[i][2 * ind + 1][j2])) {
					tr[i][ind].push_back(tr[i][2 * ind][j1]);
					++j1;
				}
				else {
					tr[i][ind].push_back(tr[i][2 * ind + 1][j2]);
					++j2;
				}
			}
		};

		build(1, 0, len - 1);
	}

	const std::function<int(const int, const int, const int, const int, const int, const int, const int)> find =
		[&](const int fq, const int ind, const int lt, const int rt, const int l, const int r, const int x) -> int
	{
		if (r < l) return 0;

		if (l == lt && r == rt) {
			auto it = upper_bound(all(tr[fq][ind]), x);
			return (it - tr[fq][ind].begin());
		}

		int m = (lt + rt) / 2;
		int res1 = find(fq, 2 * ind, lt, m, l, min(m, r), x);
		int res2 = find(fq, 2 * ind + 1, m + 1, rt, max(l, m + 1), r, x);

		return res1 + res2;
	};

	ll ans = 0;
	for (int i = 0; i <= 10000; ++i) {
		int len = fth[i].size();
		if (!len) continue;

		for (int fq = max(1, i - k); fq <= i + k; ++fq) {
			if (fth[fq].empty()) continue;

			for (int j = 0; j < len; ++j) {
				s_station s(fth[i][j]);
				auto it1 = upper_bound(all(fth[fq]), s);
				s.x += fth[i][j].r;
				auto it2 = lower_bound(all(fth[fq]), s);
				if (it2 == fth[fq].end()) --it2;
				if (it2 > fth[fq].begin() && it2->x > s.x) --it2;

				if (it1 == fth[fq].end() || it2 < it1 || it2->x > s.x) continue;

				int res = find(fq, 1, 0, fth[fq].size() - 1, it1 - fth[fq].begin(), it2 - fth[fq].begin(), fth[i][j].x);

				ans += res;
			}
		}
	}

	cout << ans;

	return 0;
}


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <algorithm>
#include <queue>
#include <cstring>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>
using namespace __gnu_pbds;

#ifdef ONLINE_JUDGE
#define freopen(N, M, Q)
#endif

#define ll long long
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define all(N) N.begin(), N.end()

using namespace std;

struct radio {
	int pos, rad, fq;
	radio() {}
	bool operator<(const radio &a) {
		return rad < a.rad;
	}
};

template<typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,
	tree_order_statistics_node_update>;

ordered_set<int> freq[10005];

int main() {
	ios_base::sync_with_stdio(false);
	freopen("input.txt", "r", stdin);

	int n, k;
	cin >> n >> k;

	radio a[n];
	for (int i = 0; i < n; i++) {
		cin >> a[i].pos >> a[i].rad >> a[i].fq;
		freq[a[i].fq].insert(a[i].pos);
	}

	sort(a, a + n);

	int ans = 0;
	for (int i = 0; i < n; i++) {
		for (int j = max(1, a[i].fq - k); j <= min(10000, a[i].fq + k); j++) {
			ans += freq[j].order_of_key(a[i].pos + a[i].rad + 1) - freq[j].order_of_key(a[i].pos - a[i].rad);
		}
		freq[a[i].fq].erase(a[i].pos);
	}

	// We cound pairs (a, a)
	cout << ans - n << endl;
	return 0;
}


#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

struct station {
    long long x, r, l;
    station() : x(0), r(0), l(0) {}
    station(long long a, long long b, long long c) : x (a), r(b), l(c) {}
};

bool isBad(station &a, station &b, long long bound) {
    if (min(a.r, b.r) >= abs(a.x-b.x)
        && abs(a.l-b.l) <= bound)
            return true;
    return false;
}

int main()
{
    long long n, k;
    cin >> n >> k;

    vector<station> line;
    for (long long i = 0; i < n; i++) {
        long long a, b, c;
        cin >> a >> b >> c;
        line.push_back(station(a, b, c));
    }

    //ascending
    sort(line.begin(), line.end(), [](station &a, station &b) {
       return a.x < b.x;
    });

    long long ans = 0;
    for (long long i = 0; i < line.size(); i++)
        for (long long j = i+1; j < line.size(); j++) {
            if (min(line[i].r , line[j].r) < abs(line[i].x < line[j].x)) break;
            else if (isBad(line[i], line[j], k)) ans++;
        }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <algorithm>
#include <queue>
#include <cstring>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>
using namespace __gnu_pbds;

#ifdef ONLINE_JUDGE
#define freopen(N, M, Q)
#endif

#define ll long long
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define all(N) N.begin(), N.end()

using namespace std;

struct radio {
	int pos, rad, fq;
	radio() {}
	bool operator<(const radio &a) {
		return rad < a.rad;
	}
};

template<typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,
	tree_order_statistics_node_update>;

ordered_set<int> freq[10005];

int main() {
	ios_base::sync_with_stdio(false);
	freopen("input.txt", "r", stdin);

	int n, k;
	cin >> n >> k;

	radio a[n];
	for (int i = 0; i < n; i++) {
		cin >> a[i].pos >> a[i].rad >> a[i].fq;
		freq[a[i].fq].insert(a[i].pos);
	}

	sort(a, a + n);

	ll ans = 0;
	for (int i = 0; i < n; i++) {
		for (int j = max(1, a[i].fq - k); j <= min(10000, a[i].fq + k); j++) {
			ans += freq[j].order_of_key(a[i].pos + a[i].rad + 1) - freq[j].order_of_key(a[i].pos - a[i].rad);
		}
		freq[a[i].fq].erase(a[i].pos);
	}

	// We cound pairs (a, a)
	cout << ans - n << endl;
	return 0;
}


#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

struct station {
    long long x, r, l;
    station() : x(0), r(0), l(0) {}
    station(long long a, long long b, long long c) : x (a), r(b), l(c) {}
};

bool isBad(station &a, station &b, long long bound) {
    if (min(a.r, b.r) >= abs(a.x-b.x)
        && abs(a.l-b.l) <= bound)
            return true;
    return false;
}

int main()
{
    long long n, k;
    cin >> n >> k;

    vector<station> line;
    for (long long i = 0; i < n; i++) {
        long long a, b, c;
        cin >> a >> b >> c;
        line.push_back(station(a, b, c));
    }

    long long ans = 0;
    for (long long i = 0; i < line.size(); i++)
        for (long long j = i+1; j < line.size(); j++) {
            if (isBad(line[i], line[j], k)) ans++;
        }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <algorithm>
#include <queue>
#include <cstring>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>
using namespace __gnu_pbds;

#ifdef ONLINE_JUDGE
#define freopen(N, M, Q)
#endif

#define ll long long
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define all(N) N.begin(), N.end()

using namespace std;

struct radio {
	int pos, rad, fq;
	radio() {}
	bool operator<(const radio &a) {
		return rad < a.rad;
	}
};

template<typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag,
	tree_order_statistics_node_update>;

ordered_set<int> freq[10005];

int main() {
	ios_base::sync_with_stdio(false);
	freopen("input.txt", "r", stdin);

	int n, k;
	cin >> n >> k;

	radio a[n];
	for (int i = 0; i < n; i++) {
		cin >> a[i].pos >> a[i].rad >> a[i].fq;
		freq[a[i].fq].insert(a[i].pos);
	}

	//sort(a, a + n);

	ll ans = 0;
	for (int i = 0; i < n; i++) {
		for (int j = max(1, a[i].fq - k); j <= min(10000, a[i].fq + k); j++) {
			ans += freq[j].order_of_key(a[i].pos + a[i].rad + 1) - freq[j].order_of_key(a[i].pos - a[i].rad);
		}
		freq[a[i].fq].erase(a[i].pos);
	}

	// We cound pairs (a, a)
	cout << ans - n << endl;
	return 0;
}


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

struct Station {
    int x, r, f;
    int a, b, c;
};

class SegmentTree {
public:
    vector<int> data;
    int n;

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

    void update(int idx, int val) {
        idx += n;
        data[idx] += val;

        while (idx > 1) {
            idx >>= 1;
            data[idx] = data[idx<<1] + data[idx<<1|1];
        }
    }

    int range(int left, int right) {
        left += n;
        right += n;

        int result = 0;
        while (left < right) {
            if (left & 1) result += data[left++];
            if (right & 1) result += data[--right];
            left >>= 1;
            right >>= 1;
        }
        return result;
    }
};

enum class Type {
    Add, Remove
};

struct Event {
    Type type;
    int pos;
    int val;
    int freq;
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.precision(10);
    cout << fixed;

    int n, k;
    cin >> n >> k;

    vector<Station> stations(n);
    for (int i = 0; i < n; i++) {
        cin >> stations[i].x >> stations[i].r >> stations[i].f;
    }

    set<int> all_pos;
    for (auto station : stations) {
        all_pos.insert(station.x - station.r);
        all_pos.insert(station.x);
        all_pos.insert(station.x + station.r);
    }
    vector<int> ordered(all_pos.begin(), all_pos.end());
    for (auto &station : stations) {
        station.a = lower_bound(ordered.begin(), ordered.end(), station.x - station.r) - ordered.begin();
        station.b = lower_bound(ordered.begin(), ordered.end(), station.x) - ordered.begin();
        station.c = lower_bound(ordered.begin(), ordered.end(), station.x + station.r) - ordered.begin();
    }

    vector<vector<Station>> stations_by_freq(10001);
    for (auto e : stations) {
        stations_by_freq[e.f].push_back(e);
    }

    long long result = 0;
    for (int i = 1; i < stations_by_freq.size(); i++) {
        if (stations_by_freq[i].empty()) continue;

        vector<Station> cur;
        // vector<Station> right, left;
        // left = stations_by_freq[i];
        for (int j = max(1, i - k); j <= min((int)stations_by_freq.size() - 1, i + k); j++) {
            for (auto e : stations_by_freq[j]) {
                cur.push_back(e);
            }
        }

        // sort(left.begin(), left.end(), [](auto s, auto t){ return s.r < t.r; });
        sort(cur.begin(), cur.end(), [i](auto s, auto t){
                if (s.r >= t.r) return true;
                // if (s.r == t.r) return t.f == i;
                return false;
                });

        SegmentTree st(ordered.size() + 3);

        for (auto e : cur) {
            if (e.f == i) {
                result += st.range(e.a, e.c + 1);
            }
            st.update(e.b, 1);
        }
    }

    cout << result << endl;
    return 0;
}


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

struct Station {
    int x, r, f;
    int a, b, c;
    int idx;
};

class SegmentTree {
public:
    vector<int> data;
    int n;

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

    void update(int idx, int val) {
        idx += n;
        data[idx] += val;

        while (idx > 1) {
            idx >>= 1;
            data[idx] = data[idx<<1] + data[idx<<1|1];
        }
    }

    int range(int left, int right) {
        left += n;
        right += n;

        int result = 0;
        while (left < right) {
            if (left & 1) result += data[left++];
            if (right & 1) result += data[--right];
            left >>= 1;
            right >>= 1;
        }
        return result;
    }

    void clear() {
        for (auto &i : data) i = 0;
    }
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.precision(10);
    cout << fixed;

    int n, k;
    cin >> n >> k;

    vector<Station> stations(n);
    for (int i = 0; i < n; i++) {
        cin >> stations[i].x >> stations[i].r >> stations[i].f;
        stations[i].idx = i;
    }

    set<int> all_pos;
    for (auto station : stations) {
        all_pos.insert(station.x - station.r);
        all_pos.insert(station.x);
        all_pos.insert(station.x + station.r);
    }
    vector<int> ordered(all_pos.begin(), all_pos.end());
    for (auto &station : stations) {
        station.a = lower_bound(ordered.begin(), ordered.end(), station.x - station.r) - ordered.begin();
        station.b = lower_bound(ordered.begin(), ordered.end(), station.x) - ordered.begin();
        station.c = lower_bound(ordered.begin(), ordered.end(), station.x + station.r) - ordered.begin();
    }

    vector<SegmentTree> st(10030, ordered.size() + 3);

    sort(stations.begin(), stations.end(), [](auto s, auto t){ return s.r > t.r; });

    long long result = 0;
    for (auto s : stations) {
        for (int f = s.f - k; f <= s.f + k; f++) {
            result += st[f + 10].range(s.a, s.c + 1);
        }
        st[s.f + 10].update(s.b, 1);
    }

    cout << result << endl;
    return 0;
}


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

struct Station {
    int x, r, f;
    int a, b, c;
    int idx;
};

class SegmentTree {
public:
    vector<int> data;
    int n;

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

    void update(int idx, int val) {
        idx += n;
        data[idx] += val;

        while (idx > 1) {
            idx >>= 1;
            data[idx] = data[idx<<1] + data[idx<<1|1];
        }
    }

    int range(int left, int right) {
        left += n;
        right += n;

        int result = 0;
        while (left < right) {
            if (left & 1) result += data[left++];
            if (right & 1) result += data[--right];
            left >>= 1;
            right >>= 1;
        }
        return result;
    }

    void clear() {
        for (auto &i : data) i = 0;
    }
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.precision(10);
    cout << fixed;

    int n, k;
    cin >> n >> k;

    vector<Station> stations(n);
    for (int i = 0; i < n; i++) {
        cin >> stations[i].x >> stations[i].r >> stations[i].f;
        stations[i].idx = i;
    }

    set<int> all_pos;
    for (auto station : stations) {
        all_pos.insert(station.x - station.r);
        all_pos.insert(station.x);
        all_pos.insert(station.x + station.r);
    }
    vector<int> ordered(all_pos.begin(), all_pos.end());
    for (auto &station : stations) {
        station.a = lower_bound(ordered.begin(), ordered.end(), station.x - station.r) - ordered.begin();
        station.b = lower_bound(ordered.begin(), ordered.end(), station.x) - ordered.begin();
        station.c = lower_bound(ordered.begin(), ordered.end(), station.x + station.r) - ordered.begin();
    }

    vector<vector<Station>> stations_by_freq(10001);
    for (auto e : stations) {
        stations_by_freq[e.f].push_back(e);
    }

    long long result = 0;
    SegmentTree st(ordered.size() + 3);
    for (int i = 1; i < stations_by_freq.size(); i++) {
        if (stations_by_freq[i].empty()) continue;

        vector<Station> cur;
        for (int j = max(1, i - k); j <= min((int)stations_by_freq.size() - 1, i + k); j++) {
            for (auto e : stations_by_freq[j]) {
                cur.push_back(e);
            }
        }

        sort(cur.begin(), cur.end(), [i](auto s, auto t){
                if (s.r > t.r) return true;
                if (s.r == t.r) return s.idx < t.idx;
                return false;
                });

        st.clear();

        for (auto e : cur) {
            if (e.f == i) {
                result += st.range(e.a, e.c + 1);
            }
            st.update(e.b, 1);
        }
    }

    cout << result << endl;
    return 0;
}


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

struct Station {
    int x, r, f;
    int a, b, c;
    int idx;
};

class SegmentTree {
public:
    vector<int> data;
    int n;

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

    void update(int idx, int val) {
        idx += n;
        data[idx] += val;

        while (idx > 1) {
            idx >>= 1;
            data[idx] = data[idx<<1] + data[idx<<1|1];
        }
    }

    int range(int left, int right) {
        left += n;
        right += n;

        int result = 0;
        while (left < right) {
            if (left & 1) result += data[left++];
            if (right & 1) result += data[--right];
            left >>= 1;
            right >>= 1;
        }
        return result;
    }
};

enum class Type {
    Add, Remove
};

struct Event {
    Type type;
    int pos;
    int val;
    int freq;
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.precision(10);
    cout << fixed;

    int n, k;
    cin >> n >> k;

    vector<Station> stations(n);
    for (int i = 0; i < n; i++) {
        cin >> stations[i].x >> stations[i].r >> stations[i].f;
        stations[i].idx = i;
    }

    set<int> all_pos;
    for (auto station : stations) {
        all_pos.insert(station.x - station.r);
        all_pos.insert(station.x);
        all_pos.insert(station.x + station.r);
    }
    vector<int> ordered(all_pos.begin(), all_pos.end());
    for (auto &station : stations) {
        station.a = lower_bound(ordered.begin(), ordered.end(), station.x - station.r) - ordered.begin();
        station.b = lower_bound(ordered.begin(), ordered.end(), station.x) - ordered.begin();
        station.c = lower_bound(ordered.begin(), ordered.end(), station.x + station.r) - ordered.begin();
    }

    vector<vector<Station>> stations_by_freq(10001);
    for (auto e : stations) {
        stations_by_freq[e.f].push_back(e);
    }

    long long result = 0;
    for (int i = 1; i < stations_by_freq.size(); i++) {
        if (stations_by_freq[i].empty()) continue;

        vector<Station> cur;
        // vector<Station> right, left;
        // left = stations_by_freq[i];
        for (int j = max(1, i - k); j <= min((int)stations_by_freq.size() - 1, i + k); j++) {
            for (auto e : stations_by_freq[j]) {
                cur.push_back(e);
            }
        }

        // sort(left.begin(), left.end(), [](auto s, auto t){ return s.r < t.r; });
        sort(cur.begin(), cur.end(), [i](auto s, auto t){
                if (s.r > t.r) return true;
                if (s.r == t.r) return s.idx < t.idx;
                return false;
                });

        SegmentTree st(ordered.size() + 3);

        for (auto e : cur) {
            if (e.f == i) {
                result += st.range(e.a, e.c + 1);
            }
            st.update(e.b, 1);
        }
    }

    cout << result << endl;
    return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

struct Station {
    int x, r, f;
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.precision(10);
    cout << fixed;

    int n, k;
    cin >> n >> k;
    vector<Station> stations(n);
    for (int i = 0; i < n; i++) {
        cin >> stations[i].x >> stations[i].r >> stations[i].f;
    }

    vector<ordered_set> st(10030);
    sort(stations.begin(), stations.end(), [](auto s, auto t){ return s.r > t.r; });
    long long result = 0;
    for (auto s : stations) {
        for (int f = s.f - k; f <= s.f + k; f++) {
            result += st[f + 10].order_of_key(s.x + s.r + 1) - st[f + 10].order_of_key(s.x - s.r);
        }
        st[s.f + 10].insert(s.x);
    }

    cout << result << endl;
    return 0;
}


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

struct Station {
    int x, r, f;
    int a, b, c;
    int idx;
};

class SegmentTree {
public:
    vector<int> data;
    int n;

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

    void update(int idx, int val) {
        idx += n;
        data[idx] += val;

        while (idx > 1) {
            idx >>= 1;
            data[idx] = data[idx<<1] + data[idx<<1|1];
        }
    }

    int range(int left, int right) {
        left += n;
        right += n;

        int result = 0;
        while (left < right) {
            if (left & 1) result += data[left++];
            if (right & 1) result += data[--right];
            left >>= 1;
            right >>= 1;
        }
        return result;
    }

    void clear() {
        for (auto &i : data) i = 0;
    }
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.precision(10);
    cout << fixed;

    int n, k;
    cin >> n >> k;

    vector<Station> stations(n);
    for (int i = 0; i < n; i++) {
        cin >> stations[i].x >> stations[i].r >> stations[i].f;
        stations[i].idx = i;
    }

    set<int> all_pos;
    for (auto station : stations) {
        all_pos.insert(station.x - station.r);
        all_pos.insert(station.x);
        all_pos.insert(station.x + station.r);
    }
    vector<int> ordered(all_pos.begin(), all_pos.end());
    for (auto &station : stations) {
        station.a = lower_bound(ordered.begin(), ordered.end(), station.x - station.r) - ordered.begin();
        station.b = lower_bound(ordered.begin(), ordered.end(), station.x) - ordered.begin();
        station.c = lower_bound(ordered.begin(), ordered.end(), station.x + station.r) - ordered.begin();
    }

    vector<vector<Station>> stations_by_freq(10001);
    for (auto e : stations) {
        stations_by_freq[e.f].push_back(e);
    }

    if (n > 10000) return 0;
    long long result = 0;
    SegmentTree st(ordered.size() + 3);
    for (int i = 1; i < stations_by_freq.size(); i++) {
        if (stations_by_freq[i].empty()) continue;

        vector<Station> cur;
        for (int j = max(1, i - k); j <= min((int)stations_by_freq.size() - 1, i + k); j++) {
            for (auto e : stations_by_freq[j]) {
                cur.push_back(e);
            }
        }

        sort(cur.begin(), cur.end(), [i](auto s, auto t){
                if (s.r > t.r) return true;
                if (s.r == t.r) return s.idx < t.idx;
                return false;
                });

        st.clear();

        for (auto e : cur) {
            if (e.f == i) {
                result += st.range(e.a, e.c + 1);
            }
            st.update(e.b, 1);
        }
    }

    cout << result << endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define ll int
#define vl vector<ll>

#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

#ifndef ONLINE_JUDGE
#  define dbg(x) (cerr << #x << " = " << (x) << endl)
#define dbg2(x,y) (cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl)
#else
#  define dbg(x) 0
#define dbg2(x,y) 0
#endif

#define N 123456
#define pii pair<int,int>

typedef tree<
pii,
    null_type,
    less<pii>,
    rb_tree_tag,
    tree_order_statistics_node_update>ordered_set;

tuple<ll,ll,ll>t[N];
map<ll,ordered_set>mp;
ll x[N],r[N],f[N];

ll getCount(ll idx,ll l,ll r){
    dbg2(l,r);
    dbg(mp[idx].size());
    auto st=mp[idx].lower_bound({l,0});
    if(st==mp[idx].end())
        return 0;
    auto en=mp[idx].lower_bound({r+1,0});
    if(en==mp[idx].begin())
        return 0;
    en--;
    ll val=mp[idx].order_of_key(*en)-mp[idx].order_of_key(*st)+1;
    dbg(val);
    return val;
}

int main(){

    ll n,i,j,k;cin>>n>>k;
    for(i=1;i<=n;i++){
        ll x,r,f;cin>>x>>r>>f;
        t[i]=make_tuple(r,x,f);
    }

    sort(t+1,t+1+n);

    for(i=1;i<=n;i++){
        r[i]=get<0>(t[i]);
        x[i]=get<1>(t[i]);
        f[i]=get<2>(t[i]);

    }

    mp[f[n]].insert({x[n],n});

    ll ans=0;
    for(i=n-1;i>=1;i--){
        for(j=f[i]-k;j<=f[i]+k;j++){
            dbg(j);
            ans+=getCount(j,x[i]-r[i],x[i]+r[i]);
        }
        dbg(ans);
        mp[f[i]].insert({x[i],i});
    }
    cout<<ans;
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define vl vector<ll>

#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

#ifndef ONLINE_JUDGE
#  define dbg(x) (cerr << #x << " = " << (x) << endl)
#define dbg2(x,y) (cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl)
#else
#  define dbg(x) 0
#define dbg2(x,y) 0
#endif

#define N 123456
#define pii pair<int,int>

typedef tree<
pii,
    null_type,
    less<pii>,
    rb_tree_tag,
    tree_order_statistics_node_update>ordered_set;

tuple<ll,ll,ll>t[N];
map<ll,ordered_set>mp;
ll x[N],r[N],f[N];

ll getCount(ll idx,ll l,ll r){
    dbg2(l,r);
    dbg(mp[idx].size());
    auto st=mp[idx].lower_bound({l,0});
    if(st==mp[idx].end())
        return 0;
    auto en=mp[idx].lower_bound({r+1,0});
    if(en==mp[idx].begin())
        return 0;
    en--;
    ll val=mp[idx].order_of_key(*en)-mp[idx].order_of_key(*st)+1;
    dbg(val);
    return val;
}

int main(){

    ll n,i,j,k;cin>>n>>k;
    for(i=1;i<=n;i++){
        ll x,r,f;cin>>x>>r>>f;
        t[i]=make_tuple(r,x,f);
    }

    sort(t+1,t+1+n);

    for(i=1;i<=n;i++){
        r[i]=get<0>(t[i]);
        x[i]=get<1>(t[i]);
        f[i]=get<2>(t[i]);

    }

    mp[f[n]].insert({x[n],n});

    ll ans=0;
    for(i=n-1;i>=1;i--){
        for(j=f[i]-k;j<=f[i]+k;j++){
            dbg(j);
            ans+=getCount(j,x[i]-r[i],x[i]+r[i]);
        }
        dbg(ans);
        mp[f[i]].insert({x[i],i});
    }
    cout<<ans;
}


#include<bits/stdc++.h>
using namespace std;
#define ll int
#define vl vector<ll>

#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

#ifndef ONLINE_JUDGE
#  define dbg(x) (cerr << #x << " = " << (x) << endl)
#define dbg2(x,y) (cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl)
#else
#  define dbg(x) 0
#define dbg2(x,y) 0
#endif

#define N 123456
#define pii pair<int,int>

typedef tree<
pii,
    null_type,
    less<pii>,
    rb_tree_tag,
    tree_order_statistics_node_update>ordered_set;

tuple<ll,ll,ll>t[N];
map<ll,ordered_set>mp;
ll x[N],r[N],f[N];

ll getCount(ll idx,ll l,ll r){
    dbg2(l,r);
    auto st=mp[idx].lower_bound({l,0});
    if(st==mp[idx].end())
        return 0;
    auto en=mp[idx].upper_bound({r,0});
    if(en==mp[idx].begin())
        return 0;
    en--;
    ll val=mp[idx].order_of_key(*en)-mp[idx].order_of_key(*st)+1;
    return val;
}

int main(){

    ll n,i,j,k;cin>>n>>k;
    for(i=1;i<=n;i++){
        ll x,r,f;cin>>x>>r>>f;
        t[i]=make_tuple(r,x,f);
    }

    sort(t+1,t+1+n);

    for(i=1;i<=n;i++){
        r[i]=get<0>(t[i]);
        x[i]=get<1>(t[i]);
        f[i]=get<2>(t[i]);

    }

    mp[f[n]].insert({x[n],n});

    ll ans=0;
    for(i=n-1;i>=1;i--){
        for(j=f[i]-k;j<=f[i]+k;j++){
            dbg(j);
            ans+=getCount(j,x[i]-r[i],x[i]+r[i]);
        }
        dbg(ans);
        mp[f[i]].insert({x[i],i});
    }
    cout<<ans;
}


#include<bits/stdc++.h>
using namespace std;
#define ll int
#define vl vector<ll>

#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

#ifndef ONLINE_JUDGE
#  define dbg(x) (cerr << #x << " = " << (x) << endl)
#define dbg2(x,y) (cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl)
#else
#  define dbg(x) 0
#define dbg2(x,y) 0
#endif

#define N 123456
#define pii pair<int,int>

typedef tree<
pii,
    null_type,
    less<pii>,
    rb_tree_tag,
    tree_order_statistics_node_update>ordered_set;

tuple<ll,ll,ll>t[N];
map<ll,ordered_set>mp;
ll x[N],r[N],f[N];

ll getCount(ll idx,ll l,ll r){
    dbg2(l,r);
    dbg(mp[idx].size());
    auto st=mp[idx].lower_bound({l,0});
    if(st==mp[idx].end())
        return 0;
    auto en=mp[idx].lower_bound({r+1,0});
    if(en==mp[idx].begin())
        return 0;
    en--;
    ll val=mp[idx].order_of_key(*en)-mp[idx].order_of_key(*st)+1;
    dbg(val);
    return val;
}

int main(){

    ll n,i,j,k;cin>>n>>k;
    for(i=1;i<=n;i++){
        ll x,r,f;cin>>x>>r>>f;
        t[i]=make_tuple(r,x,f);
    }

    sort(t+1,t+1+n);

    for(i=1;i<=n;i++){
        r[i]=get<0>(t[i]);
        x[i]=get<1>(t[i]);
        f[i]=get<2>(t[i]);
        cout<<r[i]<<" "<<x[i]<<" "<<f[i]<<endl;
    }

    mp[f[n]].insert({x[n],n});

    ll ans=0;
    for(i=n-1;i>=1;i--){
        for(j=f[i]-k;j<=f[i]+k;j++){
            dbg(j);
            ans+=getCount(j,x[i]-r[i],x[i]+r[i]);
        }
        dbg(ans);
        mp[f[i]].insert({x[i],i});
    }
    cout<<ans;
}


#include<bits/stdc++.h>
using namespace std;
#define ll int
#define vl vector<ll>

#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

#ifndef ONLINE_JUDGE
#  define dbg(x) (cerr << #x << " = " << (x) << endl)
#define dbg2(x,y) (cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl)
#else
#  define dbg(x) 0
#define dbg2(x,y) 0
#endif

#define N 123456
#define pii pair<int,int>

typedef tree<
pii,
    null_type,
    less<pii>,
    rb_tree_tag,
    tree_order_statistics_node_update>ordered_set;

tuple<ll,ll,ll>t[N];
map<ll,ordered_set>mp;
ll x[N],r[N],f[N];

ll getCount(ll idx,ll l,ll r){
    dbg2(l,r);
    auto st=mp[idx].lower_bound({l,0});
    if(st==mp[idx].end())
        return 0;
    auto en=mp[idx].upper_bound({r,0});
    if(en==mp[idx].begin())
        return 0;
    en--;
    ll val=mp[idx].order_of_key(*en)-mp[idx].order_of_key(*st)+1;
    return val;
}

int main(){

    ll n,i,j,k;cin>>n>>k;
    for(i=1;i<=n;i++){
        ll x,r,f;cin>>x>>r>>f;
        t[i]=make_tuple(r,x,f);
    }

    sort(t+1,t+1+n);

    for(i=1;i<=n;i++){
        r[i]=get<0>(t[i]);
        x[i]=get<1>(t[i]);
        f[i]=get<2>(t[i]);
        cout<<r[i]<<" "<<x[i]<<" "<<f[i]<<endl;
    }

    mp[f[n]].insert({x[n],n});

    ll ans=0;
    for(i=n-1;i>=1;i--){
        for(j=f[i]-k;j<=f[i]+k;j++){
            dbg(j);
            ans+=getCount(j,x[i]-r[i],x[i]+r[i]);
        }
        dbg(ans);
        mp[f[i]].insert({x[i],i});
    }
    cout<<ans;
}


#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back

using namespace std;
typedef pair<int,int> pii;
typedef pair<int,pii> pi3;
typedef vector<int> VI;
typedef long long INT;

#define NN 100010
#define MM 11000
int x[NN],r[NN],f[NN];
int sz[NN];
VI B[MM];
pi3 p[NN];
VI adj[NN];

void update(int u,int id){
	while(u<sz[id]+5){
		B[id][u]++;
		u+=u&(-u);
	}
}

int calc(int u,int id){
	int ans=0;
	while(u>0){
		ans+=B[id][u];
		u-=u&(-u);
	}
	return ans;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&x[i],&r[i],&f[i]);
		p[i]=pi3(r[i],pii(x[i],f[i]));
	}
	sort(p+1,p+n+1);
	for(int i=1;i<=n;i++){
		r[i]=p[i].x;
		x[i]=p[i].y.x;
		f[i]=p[i].y.y;
	}
	for(int i=n;i>=1;i--){
		adj[f[i]].pb(x[i]);
		for(int j=max(1,f[i]-k);j<=f[i]+k;j++){
			adj[j].pb(r[i]+x[i]);
			adj[j].pb(x[i]-r[i]-1);
		}
	}
	for(int i=1;i<MM;i++){
		sort(adj[i].begin(),adj[i].end());
		adj[i].resize(unique(adj[i].begin(),adj[i].end())-adj[i].begin());
		sz[i]=adj[i].size();
		B[i].resize(sz[i]+10);
	}
	INT ans=0;
	for(int i=n;i>=1;i--){
		for(int j=max(1,f[i]-k);j<=k+f[i];j++){
			int A=lower_bound(adj[j].begin(),adj[j].end(),r[i]+x[i])-adj[j].begin();
			int B=lower_bound(adj[j].begin(),adj[j].end(),-1-r[i]+x[i])-adj[j].begin();
			ans+=calc(1+A,j);
			ans-=calc(1+B,j);
		}
		int C=lower_bound(adj[f[i]].begin(),adj[f[i]].end(),x[i])-adj[f[i]].begin();
		update(1+C,f[i]);
	}
	printf("%I64d\n",ans);
    return 0;
}


#include <bits/stdc++.h>

using namespace std;
typedef long long INT;

#define NN 100
INT p[NN];
int n;

int main(){
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	INT x,y;
	scanf("%I64d%I64d",&x,&y);
	INT X=x;
	for(int i=2;(INT)i*i<=x;i++){
		if(X%i==0){
			p[++n]=i;
			while(X%i==0) X/=i;
		}
	}
	if(X>1) p[++n]=X;
	INT ans=0;
	while(y){
		INT z=__gcd(x,y);
		x/=z;
		y/=z;
		INT mn=y;
		for(int i=1;i<=n;i++){
			if(x%p[i]) continue;
			mn=min(mn,y%p[i]);
		}
		ans+=mn;
		y-=mn;
	}
	printf("%I64d\n",ans);
}


#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define pb push_back
#define y second
#define x first

using namespace std;
using INT=long long;
using VI=vector<int>;
using pii=pair<int, int>;
template<typename A, typename B> inline void smin(A &a, const B &b) {if(a>b) a=b;}
template<typename A, typename B> inline void smax(A &a, const B &b) {if(a<b) a=b;}

#define NN 101010
#define MM 404040
#define ls (u<<1)
#define rs (ls|1)
#define mid (L+R>>1)

int id[NN];
int x[NN], y[NN], xmn[MM], xmx[MM], ymn[MM], ymx[MM];

inline void build(int u, int L, int R, int dp=0) {
	if(L+1==R) {
		xmn[u]=xmx[u]=x[id[L]];
		ymn[u]=ymx[u]=y[id[L]];
		return ;
	}

	if(dp) nth_element(id+L, id+mid, id+R, [](int u, int v) {return x[u]<x[v];});
	else nth_element(id+L, id+mid, id+R, [](int u, int v) {return y[u]<y[v];});

	dp^=1;
	build(ls, L, mid, dp);
	build(rs, mid, R, dp);

	xmn[u]=min(xmn[ls], xmn[rs]), xmx[u]=max(xmx[ls], xmx[rs]);
	ymn[u]=min(ymn[ls], ymn[rs]), ymx[u]=max(ymx[ls], ymx[rs]);
}

int xx, yy, sz[MM];

void update(int u, int L, int R) {
	if(xx<xmn[u] || xx>xmx[u]) return ;
	if(yy<ymn[u] || yy>ymx[u]) return ;
	if(L+1==R) sz[u]=1;
	else {
		update(ls, L, mid);
		update(rs, mid, R);
		sz[u]=sz[ls]+sz[rs];
	}
}
int Xmn, Xmx, Ymn, Ymx;
int calc(int u, int L, int R) {
	if(Xmx<xmn[u] || xmx[u]<Xmn) return 0;
	if(Ymx<ymn[u] || ymx[u]<Ymn) return 0;
	if(Xmn<=xmn[u] && xmx[u]<=Xmx && Ymn<=ymn[u] && ymx[u]<=Ymx) return sz[u];
	return calc(ls, L, mid)+calc(rs, mid, R);
}

int X[NN], R[NN], F[NN], I[NN];

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int n, k; scanf("%d %d", &n, &k);
	for(int i=1; i<=n; i++) {
		scanf("%d %d %d", X+i, R+i, F+i);
		x[i]=X[i], y[i]=F[i];
		id[i]=I[i]=i;
	}

	build(1, 1, n+1);
	sort(I+1, I+n+1, [&](int u, int v) {return R[u]>R[v];});

	srand(time(0));

	INT ans=0;
	for(int i=1, u; i<=n; i++) {
		u=I[i];
		Xmn=X[u]-R[u], Xmx=X[u]+R[u];
		Ymn=F[u]-k, Ymx=F[u]+k;
		ans+=calc(1, 1, n+1);

		xx=X[u], yy=F[u], update(1, 1, n+1);
	}
	printf("%I64d", ans);
}


#include<bits/stdc++.h>

#define NN 100100
#define MM 10020

using namespace std;

typedef long long INT;
typedef pair<int,int>pii;
typedef pair<int,pii>pi3;

vector<int>res[MM],b[MM];
pi3 p[NN];

void update(int u,int id){
	if(u==0)return ;
	for(;u<b[id].size();u+=u&-u)b[id][u]++;
}

int calc(int u,int id){
	int ans=0;
	if(u==0)return 0;
	for(;u;u-=u&-u){
		ans+=b[id][u];
	}
	return ans;
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);
#endif
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		int x,r,f;
		scanf("%d %d %d",&x,&r,&f);
		res[f].push_back(x);
		p[i]=pi3(r,pii(x,f));
	}
	sort(p+1,p+n+1);
	for(int i=1;i<MM;i++)sort(res[i].begin(),res[i].end());
	for(int i=1;i<MM;i++)for(int j=1;j<=res[i].size()+1;j++)b[i].push_back(0);

	INT ans=0;
	for(int i=n;i>=1;i--){
		int r=p[i].first;
		int x=p[i].second.first;
		int f=p[i].second.second;
		int L=max(1,x-r),R=x+r;
		for(int j=max(1,f-k);j<=f+k;j++){
			if(res[j].size()==0)continue;
			int st=lower_bound(res[j].begin(),res[j].end(),L)-res[j].begin();
			st++;
			int ed=upper_bound(res[j].begin(),res[j].end(),R)-res[j].begin();
			ans+=(calc(ed,j)-calc(st-1,j));
		}
		int id=lower_bound(res[f].begin(),res[f].end(),x)-res[f].begin();
		update(id+1,f);
	}
	cout<<ans<<endl;

	return 0;
}


//#pragma GCC optimize ("O3")
#include <bits/stdc++.h>
using namespace std;

const int N = 100005, M = 10005;

struct node {
	int sum;
	node *l, *r;

	node() :
			sum(0), l(this), r(this) {
	}

	node(int sum, node *l, node *r) :
			sum(sum), l(l), r(r) {
	}

};

node *empty = new node();

node *add(node *cur, int s, int e, int idx) {
	if (idx < s || idx > e)
		return cur;

	if (s == e) {
		return new node(cur->sum + 1, empty, empty);
	}

	int mid = s + (e - s) / 2;

	return new node(cur->sum + 1, add(cur->l, s, mid, idx),
			add(cur->r, mid + 1, e, idx));

}

int query(node *cur, node *d, int s, int e, int f, int t) {
	int sz = cur->sum - d->sum;
	if (e < f || s > t || !sz)
		return 0;

	if (s >= f && e <= t)
		return sz;

	int mid = s + (e - s) / 2;

	return query(cur->l, d->l, s, mid, f, t)
			+ query(cur->r, d->r, mid + 1, e, f, t);

}

vector<node*> freq[M];
vector<int> cor[M];
void init() {
	for (int i = 1; i <= 10000; ++i) {
		freq[i].push_back(empty);
		cor[i].push_back(0);
	}
}

struct station {
	int x, r, f;

	bool operator <(const station &s) const {
		return x < s.x;
	}
} arr[N];

int main() {
	//freopen("in.txt", "rt", stdin);
	init();
	int n, k;
	scanf("%d %d", &n, &k);
	for (int i = 0; i < n; ++i) {
		scanf("%d %d %d", &arr[i].x, &arr[i].r, &arr[i].f);
	}
	sort(arr, arr + n);
	long long ans = 0;
	for (int i = 0; i < n; ++i) {
		int ks = max(1, arr[i].f - k), ke = min(10000, arr[i].f + k);
		int s = max(arr[i].x - arr[i].r, 1);
		for (int id = ks; id <= ke; ++id) {
			vector<int> &vec = cor[id];
			int a = lower_bound(vec.begin(), vec.end(), s) - vec.begin();
			if (a < (int)vec.size()) {
				ans += query(freq[id].back(), freq[id][a - 1], 0, 2e9, arr[i].x,
						2e9);
			}
		}
		cor[arr[i].f].push_back(arr[i].x);
		freq[arr[i].f].push_back(
				add(freq[arr[i].f].back(), 0, 2e9, arr[i].x + arr[i].r));
	}
	printf("%lld", ans);
}


//#pragma GCC optimize ("O3")
#include <bits/stdc++.h>
using namespace std;

const int N = 100005, M = 10005;

struct node {
	int sum;
	node *l, *r;

	node() :
			sum(0), l(this), r(this) {
	}

	node(int sum, node *l, node *r) :
			sum(sum), l(l), r(r) {
	}

};

node *empty = new node();

node *add(node *cur, int s, int e, int idx) {
	if (idx < s || idx > e)
		return cur;

	if (s == e) {
		return new node(cur->sum + 1, empty, empty);
	}

	int mid = s + (e - s) / 2;

	return new node(cur->sum + 1, add(cur->l, s, mid, idx),
			add(cur->r, mid + 1, e, idx));

}

int query(node *cur, node *d, int s, int e, int f, int t) {
	int sz = cur->sum - d->sum;
	if (e < f || s > t || !sz)
		return 0;

	if (s >= f && e <= t)
		return sz;

	int mid = s + (e - s) / 2;

	return query(cur->l, d->l, s, mid, f, t)
			+ query(cur->r, d->r, mid + 1, e, f, t);

}

vector<node*> freq[M];
vector<int> cor[M];
void init() {
	for (int i = 1; i <= 10000; ++i) {
		freq[i].push_back(empty);
		cor[i].push_back(0);
	}
}

struct station {
	int x, r, f;

	bool operator <(const station &s) const {
		return x < s.x;
	}
} arr[N];

int main() {
	//freopen("in.txt", "rt", stdin);
	init();
	int n, k;
	scanf("%d %d", &n, &k);
	for (int i = 0; i < n; ++i) {
		scanf("%d %d %d", &arr[i].x, &arr[i].r, &arr[i].f);
	}
	sort(arr, arr + n);
	long long ans = 0;
	for (int i = 0; i < n; ++i) {
		int ks = max(1, arr[i].f - k), ke = min(10000, arr[i].f + k);
		int s = max(arr[i].x - arr[i].r, 1), e = max(arr[i].x, 1);
		for (int id = ks; id <= ke; ++id) {
			vector<int> &vec = cor[id];
			int a = lower_bound(vec.begin(), vec.end(), s) - vec.begin();
			int b = (upper_bound(vec.begin(), vec.end(), e) - vec.begin()) - 1;
			if (a < b) {
				ans += query(freq[id][b], freq[id][a], 0, 2e9, arr[i].x, 2e9);
			}
			if (a == b) {
				ans += query(freq[id][b], empty, 0, 2e9, arr[i].x, 2e9);
			}
		}
		cor[arr[i].f].push_back(arr[i].x);
		freq[arr[i].f].push_back(
				add(freq[arr[i].f].back(), 0, 2e9, arr[i].x + arr[i].r));
	}
	printf("%lld", ans);
}


//#pragma GCC optimize ("O3")
#include <bits/stdc++.h>
using namespace std;

const int N = 100005, M = 10005;

struct node {
	int sum;
	node *l, *r;

	node() :
			sum(0), l(this), r(this) {
	}

	node(int sum, node *l, node *r) :
			sum(sum), l(l), r(r) {
	}

};

node *empty = new node();

node *add(node *cur, int s, int e, int idx) {
	if (idx < s || idx > e)
		return cur;

	if (s == e) {
		return new node(cur->sum + 1, empty, empty);
	}

	int mid = s + (e - s) / 2;

	return new node(cur->sum + 1, add(cur->l, s, mid, idx),
			add(cur->r, mid + 1, e, idx));

}

int query(node *cur, node *d, int s, int e, int f, int t) {
	int sz = cur->sum - d->sum;
	if (e < f || s > t || !sz)
		return 0;

	if (s >= f && e <= t)
		return sz;

	int mid = s + (e - s) / 2;

	return query(cur->l, d->l, s, mid, f, t)
			+ query(cur->r, d->r, mid + 1, e, f, t);

}

vector<node*> freq[M];
vector<int> cor[M];
void init() {
	for (int i = 1; i <= 10000; ++i) {
		freq[i].push_back(empty);
		cor[i].push_back(0);
	}
}

struct station {
	int x, r, f;

	bool operator <(const station &s) const {
		return x < s.x;
	}
} arr[N];

int main() {
	//freopen("in.txt", "rt", stdin);
	init();
	int n, k;
	scanf("%d %d", &n, &k);
	for (int i = 0; i < n; ++i) {
		scanf("%d %d %d", &arr[i].x, &arr[i].r, &arr[i].f);
	}
	sort(arr, arr + n);
	long long ans = 0;
	for (int i = 0; i < n; ++i) {
		int ks = max(1, arr[i].f - k), ke = min(10000, arr[i].f + k);
		int s = max(arr[i].x - arr[i].r, 1), e = max(arr[i].x - 1, 1);
		for (int id = ks; id <= ke; ++id) {
			vector<int> &vec = cor[id];
			int a = lower_bound(vec.begin(), vec.end(), s) - vec.begin();
			int b = (upper_bound(vec.begin(), vec.end(), e) - vec.begin()) - 1;
			if (a < b) {
				ans += query(freq[id][b], freq[id][a], 0, 2e9, arr[i].x, 2e9);
			}
			if (a == b) {
				ans += query(freq[id][b], empty, 0, 2e9, arr[i].x, 2e9);
			}
		}
		cor[arr[i].f].push_back(arr[i].x);
		freq[arr[i].f].push_back(
				add(freq[arr[i].f].back(), 0, 2e9, arr[i].x + arr[i].r));
	}
	printf("%lld", ans);
}


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

#define int long long
#define f(i,n) for(int i=0;i<n;i++)
#define Fast ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define F first
#define S second

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int getrand()
{
    uniform_int_distribution<int> uid(0*1LL, 9999999999999*1LL);
    return uid(rng);
}

struct node{
    int prior,size;
    int val;
    struct node *l,*r;
};

typedef node* pnode;

int sz(pnode t){
    return t?t->size:0;
}

void upd_sz(pnode t){
    if(t) t->size=sz(t->l)+1+sz(t->r);
}

void split(pnode t,pnode &l,pnode &r,int pos){

    if(!t) (l=r=NULL);
    else if(t->val<=pos) split(t->r,t->r,r,pos),l=t;
    else split(t->l,l,t->l,pos),r=t;

    upd_sz(t);
}

void merge(pnode &t,pnode l,pnode r)
{
    if (!l || !r) t = l?l:r;
    else if (l->prior > r->prior) merge(l->r,l->r,r),t=l;
    else merge(r->l,l,r->l),t=r;

    upd_sz(t);
}

void erase(pnode & t,int key)
{
    if(!t) return;

    else if(t-> val == key)  merge(t,t->l,t->r);
    else erase (key < t->val ? t->l : t->r, key);

    upd_sz(t);
}

pnode init(int val)
{
    pnode ret = new node();
    ret->prior=rand();
    ret->size=1;
    ret->val=val;
    ret->l = ret-> r = NULL;
    return ret;
}

int range_query(pnode t,int x)
{

    if(t==NULL) return 0;

    int ans = 0;

    if(x < t->val) return range_query(t->l,x);

    return sz(t->l)+1+range_query(t->r,x);

}

void insert (pnode & t, pnode it)
{
    if (!t)
        t = it;
    else if (it->prior > t->prior)
        split (t, it->l, it->r , it->val),  t = it;
    else
        insert (it->val < t->val ? t->l : t->r, it);
}

const int N = 1e4+10;
const int NN = 1e5+10;

pnode aa[N];
pair<pair<int,int>,int> dat[NN];

bool comp(const pair<pair<int,int>,int> & a,const pair<pair<int,int>,int> & b)
{
    if(a.F.S == b.F.S) return a.F.F < b.F.F;
    return a.F.S < b.F.S;
}

signed main()
{
    Fast;

    int n,k,ans=0;

    cin >> n >> k;

    f(i,n)
    {
     cin >> dat[i].F.F >> dat[i].F.S >> dat[i].S;

     insert(aa[dat[i].S],init(dat[i].F.F));
    }

    sort(dat,dat+n,comp);

    f(i,n)
    {
      for(int j=max(1LL,dat[i].S-k);j<=min(10000*1LL,dat[i].S+k);j++)
      {
          ans+=range_query(aa[j],dat[i].F.F+dat[i].F.S)-range_query(aa[j],dat[i].F.F-dat[i].F.S-1);
      }
      erase(aa[dat[i].S],dat[i].F.F);
    }

    cout << ans-n;
}


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

#define int long long
#define f(i,n) for(int i=0;i<n;i++)
#define Fast ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define F first
#define S second

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int getrand()
{
    uniform_int_distribution<int> uid(0*1LL, 9999999999999*1LL);
    return uid(rng);
}

struct node{
    int prior,size;
    int val;
    struct node *l,*r;
};

typedef node* pnode;

int sz(pnode t){
    return t?t->size:0;
}

void upd_sz(pnode t){
    if(t) t->size=sz(t->l)+1+sz(t->r);
}

void split(pnode t,pnode &l,pnode &r,int pos){

    if(!t) return void(l=r=NULL);

    if(t->val<=pos) split(t->r,t->r,r,pos),l=t;
    else split(t->l,l,t->l,pos),r=t;

    upd_sz(t);
}

void merge(pnode &t,pnode l,pnode r)
{
    if (!l || !r) t = l?l:r;
    else if (l->prior > r->prior) merge(l->r,l->r,r),t=l;
    else merge(r->l,l,r->l),t=r;

    upd_sz(t);
}

void erase(pnode & t,int key)
{
    if(t-> val == key)  merge(t,t->l,t->r);
    else erase (key < t->val ? t->l : t->r, key);
}

pnode init(int val)
{
    pnode ret = new node();
    ret->prior=getrand();
    ret->size=1;
    ret->val=val;
    return ret;
}

int range_query(pnode t,int x)
{
    pnode a=NULL,b=NULL;

    if(t==NULL) return 0;

    split(t,a,b,x);

    int ans = 0;

    ans = sz(a);

    merge(t,a,b);

    return ans;
}

void insert (pnode & t, pnode it)
{
    if (!t)
        t = it;
    else if (it->prior > t->prior)
        split (t, it->l, it->r , it->val),  t = it;
    else
        insert (it->val < t->val ? t->l : t->r, it);
}

const int N = 1e4+10;
const int NN = 1e5+10;

pnode aa[N];
pair<pair<int,int>,int> dat[NN];

bool comp(const pair<pair<int,int>,int> & a,const pair<pair<int,int>,int> & b)
{
    if(a.F.S == b.F.S) return a.F.F < b.F.F;
    return a.F.S < b.F.S;
}

signed main()
{
    Fast;

    int n,k,ans=0;

    cin >> n >> k;

    f(i,n)
    {
     cin >> dat[i].F.F >> dat[i].F.S >> dat[i].S;

     insert(aa[dat[i].S],init(dat[i].F.F));
    }

    sort(dat,dat+n,comp);

    f(i,n)
    {
      for(int j=max(1LL,dat[i].S-k);j<=min(10000*1LL,dat[i].S+k);j++)
      {
          ans+=range_query(aa[j],dat[i].F.F+dat[i].F.S+1)-range_query(aa[j],dat[i].F.F-dat[i].F.S);
      }
      erase(aa[dat[i].S],dat[i].F.F);
    }

    cout << ans-n;
}


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

#define int long long
#define f(i,n) for(int i=0;i<n;i++)
#define Fast ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define F first
#define S second

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

int getrand()
{
    uniform_int_distribution<int> uid(0, 999999999999999);
    return uid(rng);
}

struct node{
    int prior,size;
    int val;
    struct node *l,*r;
};

typedef node* pnode;

int sz(pnode t){
    return t?t->size:0;
}

void upd_sz(pnode t){
    if(t)t->size=sz(t->l)+1+sz(t->r);
}

void split(pnode t,pnode &l,pnode &r,int pos){
    if(!t)return void(l=r=NULL);

    int curr_pos = t->val;

    if(curr_pos<=pos)
        split(t->r,t->r,r,pos),l=t;
    else
        split(t->l,l,t->l,pos),r=t;

    upd_sz(t);

}

void merge(pnode &t,pnode l,pnode r){ //l->leftarray,r->rightarray,t->resulting array
    if(!l || !r) t = l?l:r;
    else if(l->prior>r->prior)merge(l->r,l->r,r),t=l;
    else merge(r->l,l,r->l),t=r;

    upd_sz(t);
}

void erase(pnode & t,int key)
{
    if(t-> val == key)
      merge(t,t->l,t->r);

    else
        erase (key < t->val ? t->l : t->r, key);
}

pnode init(int val)
{
    pnode ret = new node();
    ret->prior=getrand();
    ret->size=1;
    ret->val=val;
    return ret;
}

int range_query(pnode t,int x)
{
    pnode a,b;

    if(t==NULL) return 0;

    split(t,a,b,x);

    int ans = 0;

    ans = sz(a);

    merge(t,a,b);

    return ans;
}

const int N = 1e4+10;
const int NN = 1e5+10;

pnode aa[N];
pair<pair<int,int>,int> data[NN];

bool comp(const pair<pair<int,int>,int> & a,const pair<pair<int,int>,int> & b)
{
    return a.F.S < b.F.S;
}

signed main()
{
    Fast;

    int n,k,ans=0;

    cin >> n >> k;

    f(i,n)
    {
     cin >> data[i].F.F >> data[i].F.S >> data[i].S;

        assert(data[i].S <= N);
        assert(i<=NN);

     if(aa[data[i].S] == NULL) aa[data[i].S] = init(data[i].F.F);
     else merge(aa[data[i].S],aa[data[i].S],init(data[i].F.F));

    }

    sort(data,data+n,comp);

    f(i,n)
    {
      for(int j=max(1LL,data[i].S-k);j<=min(10000*1LL,data[i].S+k);j++)
      {
          ans+=range_query(aa[j],data[i].F.F+data[i].F.S)-range_query(aa[j],data[i].F.F-data[i].F.S-1);
      }
      erase(aa[data[i].S],data[i].F.F);
    }

    cout << ans-n;
}


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

#define int long long
#define f(i,n) for(int i=0;i<n;i++)
#define Fast ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define F first
#define S second

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int getrand()
{
    uniform_int_distribution<int> uid(0*1LL, 9999999999999*1LL);
    return uid(rng);
}

struct node{
    int prior,size;
    int val;
    struct node *l,*r;
};

typedef node* pnode;

int sz(pnode t){
    return t?t->size:0;
}

void upd_sz(pnode t){
    if(t) t->size=sz(t->l)+1+sz(t->r);
}

void split(pnode t,pnode &l,pnode &r,int pos){

    if(!t) return void(l=r=NULL);

    if(t->val<=pos) split(t->r,t->r,r,pos),l=t;
    else split(t->l,l,t->l,pos),r=t;

    upd_sz(t);
}

void merge(pnode &t,pnode l,pnode r)
{
    if (!l || !r) t = l?l:r;
    else if (l->prior > r->prior) merge(l->r,l->r,r),t=l;
    else merge(r->l,l,r->l),t=r;

    upd_sz(t);
}

void erase(pnode & t,int key)
{
    if(t-> val == key)  merge(t,t->l,t->r);
    else erase (key < t->val ? t->l : t->r, key);
}

pnode init(int val)
{
    pnode ret = new node();
    ret->prior=getrand();
    ret->size=1;
    ret->val=val;
    return ret;
}

int range_query(pnode t,int x)
{
    pnode a=NULL,b=NULL;

    if(t==NULL) return 0;

    int ans = 0;

    if(x < t->val) return range_query(t->l,x);
    else return sz(t->l)+1+range_query(t->r,x);

}

void insert (pnode & t, pnode it)
{
    if (!t)
        t = it;
    else if (it->prior > t->prior)
        split (t, it->l, it->r , it->val),  t = it;
    else
        insert (it->val < t->val ? t->l : t->r, it);
}

const int N = 1e4+10;
const int NN = 1e5+10;

pnode aa[N];
pair<pair<int,int>,int> dat[NN];

bool comp(const pair<pair<int,int>,int> & a,const pair<pair<int,int>,int> & b)
{
    if(a.F.S == b.F.S) return a.F.F < b.F.F;
    return a.F.S < b.F.S;
}

signed main()
{
    Fast;

    int n,k,ans=0;

    cin >> n >> k;

    f(i,n)
    {
     cin >> dat[i].F.F >> dat[i].F.S >> dat[i].S;

     insert(aa[dat[i].S],init(dat[i].F.F));
    }

    sort(dat,dat+n,comp);

    f(i,n)
    {
      for(int j=max(1LL,dat[i].S-k);j<=min(10000*1LL,dat[i].S+k);j++)
      {
          ans+=range_query(aa[j],dat[i].F.F+dat[i].F.S)-range_query(aa[j],dat[i].F.F-dat[i].F.S-1);
      }
      erase(aa[dat[i].S],dat[i].F.F);
    }

    cout << ans-n;
}


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

#define int long long
#define f(i,n) for(int i=0;i<n;i++)
#define Fast ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define F first
#define S second

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int getrand()
{
    uniform_int_distribution<int> uid(0*1LL, 9999999999999*1LL);
    return uid(rng);
}

struct node{
    int prior,size;
    int val;
    struct node *l,*r;
};

typedef node* pnode;

int sz(pnode t){
    return t?t->size:0;
}

void upd_sz(pnode t){
    if(t) t->size=sz(t->l)+1+sz(t->r);
}

void split(pnode t,pnode &l,pnode &r,int pos){

    if(!t) (l=r=NULL);
    else if(t->val<=pos) split(t->r,t->r,r,pos),l=t;
    else split(t->l,l,t->l,pos),r=t;

    upd_sz(t);
}

void merge(pnode &t,pnode l,pnode r)
{
    if (!l || !r) t = l?l:r;
    else if (l->prior > r->prior) merge(l->r,l->r,r),t=l;
    else merge(r->l,l,r->l),t=r;

    upd_sz(t);
}

void erase(pnode & t,int key)
{
    if(!t) return;
    else if(t-> val == key) {pnode temp = t; merge(t,t->l,t->r); free(temp); }
    else erase (key < t->val ? t->l : t->r, key);

    upd_sz(t);
}

pnode init(int val)
{
    pnode ret = new node();
    ret->prior=getrand();
    ret->size=1;
    ret->val=val;
    return ret;
}

int range_query(pnode t,int x)
{
    pnode a=NULL,b=NULL;

    if(t==NULL) return 0;

    int ans = 0;

    if(x < t->val) return range_query(t->l,x);
    else return sz(t->l)+1+range_query(t->r,x);

}

void insert (pnode & t, pnode it)
{
    if (!t)
        t = it;
    else if (it->prior > t->prior)
        split (t, it->l, it->r , it->val),  t = it;
    else
        insert (it->val < t->val ? t->l : t->r, it);
}

const int N = 1e4+10;
const int NN = 1e5+10;

pnode aa[N];
pair<pair<int,int>,int> dat[NN];

bool comp(const pair<pair<int,int>,int> & a,const pair<pair<int,int>,int> & b)
{
    if(a.F.S == b.F.S) return a.F.F < b.F.F;
    return a.F.S < b.F.S;
}

signed main()
{
    Fast;

    int n,k,ans=0;

    cin >> n >> k;

    f(i,n)
    {
     cin >> dat[i].F.F >> dat[i].F.S >> dat[i].S;

     insert(aa[dat[i].S],init(dat[i].F.F));
    }

    sort(dat,dat+n,comp);

    f(i,n)
    {
      for(int j=max(1LL,dat[i].S-k);j<=min(10000*1LL,dat[i].S+k);j++)
      {
          ans+=range_query(aa[j],dat[i].F.F+dat[i].F.S)-range_query(aa[j],dat[i].F.F-dat[i].F.S-1);
      }
      erase(aa[dat[i].S],dat[i].F.F);
    }

    cout << ans-n;
}


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

#define int long long
#define f(i,n) for(int i=0;i<n;i++)
#define Fast ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define F first
#define S second

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

int getrand()
{
    uniform_int_distribution<int> uid(0*1LL, 99999999999*1LL);
    return uid(rng);
}

struct node{
    int prior,size;
    int val;
    struct node *l,*r;
};

typedef node* pnode;

int sz(pnode t){
    return t?t->size:0;
}

void upd_sz(pnode t){
    if(t)t->size=sz(t->l)+1+sz(t->r);
}

void split(pnode t,pnode &l,pnode &r,int pos){

    if(!t) return void(l=r=NULL);

    int curr_pos = t->val;

    if(curr_pos<=pos)
        split(t->r,t->r,r,pos),l=t;
    else
        split(t->l,l,t->l,pos),r=t;

    upd_sz(t);

}

void merge(pnode &t,pnode l,pnode r){ //l->leftarray,r->rightarray,t->resulting array

    if(!l || !r) t = l?l:r;
    else if(l->prior>r->prior)merge(l->r,l->r,r),t=l;
    else merge(r->l,l,r->l),t=r;

    upd_sz(t);
}

void erase(pnode & t,int key)
{
    if(t-> val == key)
      merge(t,t->l,t->r);

    else
        erase (key < t->val ? t->l : t->r, key);
}

pnode init(int val)
{
    pnode ret = new node();
    ret->prior=getrand();
    ret->size=1;
    ret->val=val;
    return ret;
}

int range_query(pnode t,int x)
{
    pnode a,b;

    if(t==NULL) return 0;

    split(t,a,b,x);

    int ans = 0;

    ans = sz(a);

    merge(t,a,b);

    return ans;
}

void insert (pnode & t, pnode it)
{
    if (!t)
        t = it;
    else if (it->prior > t->prior)
        split (t, it->l, it->r , it->val),  t = it;
    else
        insert (it->val < t->val ? t->l : t->r, it);
}

const int N = 1e4+10;
const int NN = 1e5+10;

pnode aa[N];
pair<pair<int,int>,int> dat[NN];

bool comp(const pair<pair<int,int>,int> & a,const pair<pair<int,int>,int> & b)
{
    return a.F.S < b.F.S;
}

signed main()
{
    Fast;

    int n,k,ans=0;

    cin >> n >> k;

    f(i,N) aa[i] = NULL;

    f(i,n)
    {
     cin >> dat[i].F.F >> dat[i].F.S >> dat[i].S;

     if(aa[dat[i].S] == NULL) aa[dat[i].S] = init(dat[i].F.F);
     else insert(aa[dat[i].S],init(dat[i].F.F));
    }

    sort(dat,dat+n,comp);

    f(i,n)
    {
      for(int j=max(1LL,dat[i].S-k);j<=min(10000*1LL,dat[i].S+k);j++)
      {
          ans+=range_query(aa[j],dat[i].F.F+dat[i].F.S)-range_query(aa[j],dat[i].F.F-dat[i].F.S-1);
      }
      erase(aa[dat[i].S],dat[i].F.F);
    }

    cout << ans-n;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;

#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>

#define int long long
#define f(i,n) for(int i=0;i<n;i++)
#define Fast ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define F first
#define S second

const int N = 1e4+10;
const int NN = 1e5+10;

ordered_set aa[N];
pair<pair<int,int>,int> dat[NN];

bool comp(const pair<pair<int,int>,int> & a,const pair<pair<int,int>,int> & b)
{
    if(a.F.S == b.F.S) return a.F.F < b.F.F;
    return a.F.S < b.F.S;
}

signed main()
{
    Fast;

    int n,k,ans=0;

    cin >> n >> k;

    f(i,n)
    {
     cin >> dat[i].F.F >> dat[i].F.S >> dat[i].S;

     aa[dat[i].S].insert(dat[i].F.F);
    }

    sort(dat,dat+n,comp);

    f(i,n)
    {
      for(int j=max(1LL,dat[i].S-k);j<=min(10000*1LL,dat[i].S+k);j++)
      {
          ans+=aa[j].order_of_key(dat[i].F.F+dat[i].F.S+1)-aa[j].order_of_key(dat[i].F.F-dat[i].F.S);

      }

      aa[dat[i].S].erase(dat[i].F.F);
    }

    cout << ans-n;
}