#include <iostream>
#include <vector>
#include <queue>
#include <set>
#include <functional>
using namespace std;

using ll = long long;

struct Edge {
    int to, cost;
};

struct State {
    int node, rem, cost;
    State(int node, int rem, int cost) :
        node(node), rem(rem), cost(cost) {}

    bool operator>(const State& s) const {
        return cost > s.cost;
    }
};

const int MAX_R = 10;
const int MAX_N = 100010;
const int INF = (1 << 28);

int cost[MAX_R][MAX_N];

vector<Edge> rev_graph[MAX_N];
set<int> nodes[MAX_R];

int n, m, r, q;

void dijkstra() {
    for (int rem = 0; rem < r; rem++) {
        priority_queue<State, vector<State>, greater<State>> que;

        for (int v = 0; v < n; v++) {
            cost[rem][v] = (v % r == rem) ? 0 : INF;
        }

        for (int v : nodes[rem]) {
            cost[rem][v] = 0;
            que.push(State(v, rem, 0));
        }

        while (!que.empty()) {
            State s = que.top(); que.pop();
            if (cost[rem][s.node] < s.cost) continue;

            for (Edge e : rev_graph[s.node]) {
                if (cost[rem][e.to] > s.cost + e.cost) {
                    cost[rem][e.to] = s.cost + e.cost;
                    que.push(State(e.to, rem, cost[rem][e.to]));
                }
            }
        }
    }
}

int main() {
    cin >> n >> m >> r >> q;

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

        rev_graph[b].push_back((Edge){a, c});
        nodes[b % r].insert(b);
    }

    dijkstra();

    ll ans = 0;
    for (int i = 0; i < q; i++) {
        ll x, y, z;
        cin >> x >> y >> z;
        x--; y--;

        ll val = 0;
        for (int r_i = 0; r_i < r; r_i++) {
            val = max(val, z - cost[r_i][x] - cost[r_i][y]);
        }
        ans += val;
    }
    cout << ans << endl;

    return 0;
}