import std.algorithm;
import std.array;
import std.ascii;
import std.container;
import std.conv;
import std.math;
import std.numeric;
import std.range;
import std.stdio;
import std.string;
import std.typecons;

void log(A...)(A arg) {
    stderr.writeln(arg);
}
int size(T)(in T s) {
    return cast(int)s.length;
}

struct Point {
    int x, y;
    int index;
};
class RangeTree {
    class Node {
        Node parent;
        Node left, right;
        int left_x, right_x;
        Point[] ys;
        override string toString() const {
            return format("([%s,%s] -> %s)", left_x, right_x, ys);
        }
    }
    Node construct(Point[] ps) {
        auto n = new Node;
        n.left_x = ps.front.x;
        n.right_x = ps.back.x;
        if(ps.length <= 1024) {
            n.ys = ps.dup.sort!"a.y < b.y".array;
            return n;
        }
        auto l = construct(ps[0 .. $ / 2]);
        auto r = construct(ps[$ / 2 .. $]);
        l.parent = n;
        r.parent = n;
        n.left = l;
        n.right = r;
        auto li = 0, ri = 0;
        while (true) {
            if (li >= l.ys.length && ri >= r.ys.length) break;
            if (li >= l.ys.length) n.ys ~= r.ys[ri++];
            else if (ri >= r.ys.length) n.ys ~= l.ys[li++];
            else {
                n.ys ~= (l.ys[li].y < r.ys[ri].y ? l.ys[li++] : r.ys[ri++]);
            }
        }
        return n;
    }
    Node root;
    this(Point[] ps) {
        ps.sort!"a.x < b.x";
        this.root = construct(ps);
    }

    /* (sx <= x <= gx && sy <= y <= gy)????????§??????(x, y)??§?±?esult???????????\??§??????. ??¢????????¢?????????????±???¨??¢???*/
    Point[] query(int sx, int sy, int gx, int gy) {
        Point[] result;
        void f(Node cur_root) {
            if (gx < cur_root.left_x || cur_root.right_x < sx) {
                // do nothing
            } else if (sx <= cur_root.left_x && cur_root.right_x <= gx) {
                auto ys = cur_root.ys;
                result ~= ys.assumeSorted!"a.y < b.y".upperBound(Point(0, sy - 1)).lowerBound(Point(0, gy + 1)).array;
            } else {
                if(cur_root.left is null || cur_root.right is null) {
                    foreach (p; cur_root.ys.assumeSorted!"a.y < b.y".upperBound(Point(0, sy - 1)).lowerBound(Point(0, gy + 1))) {
                        if (sx <= p.x && p.x <= gx && sy <= p.y && p.y <= gy) {
                            result ~= p;
                        }
                    }
                } else {
                    f(cur_root.left);
                    f(cur_root.right);
                }
            }
        }
        f(root);
        return result;
    }
}

void main() {
    int AN, BN, R;
    Point[] A, B;
    bool input() {
        scanf("%d %d %d\n", &AN, &BN, &R);
        if (AN == 0 && BN == 0) return false;
        A = new Point[AN];
        B = new Point[BN];
        foreach (i; 0 .. AN) { scanf("%d %d\n", &A[i].x, &A[i].y); }
        foreach (i; 0 .. BN) { scanf("%d %d\n", &B[i].x, &B[i].y); }
        return true;
    }
    void solve() {
        long ans = 0;
        auto tree = new RangeTree(B);
        foreach (a; A) {
            auto ns = tree.query(a.x - 4 * R, a.y - 4 * R, a.x + 4 * R, a.y + 4 * R);
            long dist_sq(in Point a, in Point b) {
                long dx = a.x - b.x;
                long dy = a.y - b.y;
                return dx * dx + dy * dy;
            }
            foreach (n; ns) {
                if (dist_sq(a, n) <= (4*R) * (4*R)) {
                    ans++;
                }
            }
        }
        writeln(ans);
    }
    while (input()) solve();
}

Measured memory_bytes: 28500