#include<bits/stdc++.h>
using namespace std;
#define sz(v) (int)(v).size()
#define all(v) (v).begin(), (v).end()
using ll = long long;
namespace Solve1D{
    /*
        Normal two pointer or sweep line something
    */
    void process()
    {
        int n,D,M; cin >> n >> D >> M;
        vector<int> a(n + 1);
        for(int i = 1; i <= n; i++){
            cin >> a[i];
        }
        sort(1 + all(a));
        ll answer = 0;
        for(int i = 1, j = 1; i <= n; i++){
            while(j < i && a[j] < a[i] - D) j++;
            answer = answer + 1ll * (i - j);
        }
        cout << answer << "\n";
    }
}
struct BIT{
    vector<int> bit;
    BIT(int n = 0): bit(n + 1) {}
    void update(int p, int val){
        for(; p < sz(bit); p += (p & (-p))){
            bit[p] += val;
        }
        return;
    }
    int get(int p){
        int ans = 0;
        if(p <= 0) return ans;
        for(; p > 0; p -= (p & (-p))){
            ans += bit[p];
        }
        return ans;
    }
    int query(int l, int r){
        return get(r) - get(l - 1);
    }
};
namespace Solve2D{
    /*
        xi <= xj, yi <= yj
        -> (1): d(i, j) = (xj - xi) + (yj - yi) = (xj + yj) - (xi + yi)
        xi >= xj, yi <= yj
        -> (2): d(i, j) = (xi - xj) + (yj - yi) = (xi - yi) - (xj - yj)
        xi <= xj, yi >= yj
        -> (3): d(i, j) = (xj - xi) + (yi - yj) = (xj - yj) - (xi - yi)
        xi >= xj, yi >= yj
        -> (4): d(i, j) = (xi - xj) + (yi - yj) = (xi + yi) - (xj - yj)
        Call d1_i = xi + yi, d2_i = xi - yi
        (1): d1_j - d1_i
        (2): d2_i - d2_j
        (3): d2_j - d2_i
        (4): d1_i - d1_j
        dist(i, j) = max( (1), (2), (3), (4) ) <= d
        for i we will need some j that:
        + d1_i - d <= d1_j <= d1_i + d
        + d2_i - d <= d2_j <= d2_i + d
        so now we fix d1_j >= d1_i - d && d1_j <= d1_i
        we will need d2_j to be in range (d2_i - d, d2_i + d)
    */
    void process()
    {
        int n,D,M; cin >> n >> D >> M;
        vector<pair<int,int>> d;
        for(int i = 0; i < n; i++){
            int a,b; cin >> a >> b;
            int d1 = a + b, d2 = a - b + M; // be careful with <= 0
            d.push_back(make_pair(d1, d2));
        }
        sort(all(d)); BIT bit(M * 2);
        ll answer = 0;
        for(int i = 0, j = 0; i < sz(d); i++){
            while(j < i && d[j].first < d[i].first - D){
                bit.update(d[j].second, -1);
                j++;
            }
            answer = answer + bit.query(d[i].second - D, min(d[i].second + D, M * 2));
            bit.update(d[i].second, 1);
        }
        cout << answer << "\n";
    }
}
namespace Solve3D{
    /*
        we had:
        + d1_i - D <= d1_j <= d1_i + D
        + d2_i - D <= d2_j <= d2_i + D
        so now we will do the same for each 3D dimension a with D change in each 2 dimension that we want to calculate
        will will for each 3D dimension (1 -> a)
        and preprocess all conditions by prefix 2D d1 will be column and d2 will be row
        or it will be a rectangle that has:
        + x1 = d1_i - newD
        + y1 = d2_i - newD
        + x2 = d1_i + newD
        + y2 = d2_i + newD
        for dimension a = current, just remember every pairs will be count (twice + itself)
            // some solution will be count this dimension like what we do with 2D array
                or just (calculated - cnt(inside current dimension)) / 2
        Time complexity: O(n * 75)
    */
    void process()
    {
        int n,D,M; cin >> n >> D >> M;
        vector<vector<vector<int>>> pref(M + 1, vector<vector<int>>(M * 2 + 1, vector<int>(M * 2 + 1)));
        vector<vector<pair<int,int>>> Query(M + 1, vector<pair<int,int>>());
        for(int i = 0; i < n; i++){
            int a,b,c; cin >> a >> b >> c;
            int d1 = b + c, d2 = b - c + M;
            pref[a][d1][d2]++;
            //cout << a <<" " << d1 <<" " << d2 << "\n";
            Query[a].push_back(make_pair(d1, d2));
        }
        for(int i = 1; i <= M; i++){
            for(int j = 1; j <= M * 2; j++){
                for(int k = 1; k <= M * 2; k++){
                    pref[i][j][k] = pref[i][j - 1][k] + pref[i][j][k - 1]
                                   -pref[i][j - 1][k - 1] + pref[i][j][k];
                }
            }
        }
        ll answer = 0;
        for(int i = 1; i <= M; i++){
            for(int a = 1; a <= i; a++){
                int nD = D - (i - a);
                if(nD < 0) continue;
                auto qpref_sum = [&](int x1, int y1, int x2, int y2) -> int{
                    return pref[a][x2][y2] - pref[a][x2][y1 - 1]
                         - pref[a][x1 - 1][y2] + pref[a][x1 - 1][y1 - 1];
                };
                ll calc = 0;
                for(pair<int,int>& cur_q : Query[i]){
                    int x1 = max(1, cur_q.first - nD);
                    int x2 = min(M * 2, cur_q.first + nD);
                    int y1 = max(1, cur_q.second - nD);
                    int y2 = min(M * 2, cur_q.second + nD);
                    //cout << x1 <<" " << y1 <<" " << x2 <<" " << y2 << "\n";
                    calc = calc + 1ll * qpref_sum(x1, y1, x2, y2);
                }
                calc = (a == i ? (calc - sz(Query[i])) / 2 : calc);
                answer = answer + calc;
            }
        }
        cout << answer << "\n";
    }
}
void solve()
{
    int B; cin >> B;
    if(B == 1) Solve1D::process();
    if(B == 2) Solve2D::process();
    if(B == 3) Solve3D::process();
}
int32_t main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    #define name "InvMOD"
    if(fopen(name".INP", "r")){
        freopen(name".INP", "r", stdin);
        freopen(name".OUT", "w", stdout);
    }
    solve();
    return 0;
}
컴파일 시 표준 에러 (stderr) 메시지
pairs.cpp: In function 'int32_t main()':
pairs.cpp:220:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  220 |         freopen(name".INP", "r", stdin);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
pairs.cpp:221:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  221 |         freopen(name".OUT", "w", stdout);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... |