#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
#define INF 1111111111

// things that handle max flow
struct edge {
    int j, flow, cap;
    edge *pair;
    edge(int j, int cap): j(j), flow(0), cap(cap), pair(NULL) {}
};

struct flow {
    int n;
    vector<edge*> *adj;
    edge **parent;
    int *flowto;
    flow(int n): n(n) {
        adj = new vector<edge*>[n];
        for (int i = 0; i < n; i++) {
            adj[i].clear();
        }
        parent = new edge*[n];
        flowto = new int[n];
    }
    void add_edge(int i, int j, int front, int back = 0) {
        // back is the capacity of the backward direction.
        // if back = 0, then edge is directed.
        edge *ef = new edge(j, front);
        edge *eb = new edge(i, back);
        ef->pair = eb;
        eb->pair = ef;
        adj[i].push_back(ef);
        adj[j].push_back(eb);
    }

    int aug(int s, int t) {
        // BFS-augment from s to t
        vector<int> queue;
        for (int i = 0; i < n; i++) flowto[i] = 0;
        queue.push_back(s);
        flowto[s] = INF;
        for (int f = 0; f < queue.size(); f++) {
            int i = queue[f];
            for (int nb = 0; nb < adj[i].size(); nb++) {
                edge *e = adj[i][nb];
                int j = e->j;
                if (!flowto[j]) {
                    int delta = e->cap - e->flow;
                    if (delta > 0) {
                        flowto[j] = min(flowto[i], delta);
                        parent[j] = e;
                        if (j == t) return flowto[j];
                        queue.push_back(j);
                    }
                }
            }
        }
        return 0;
    }

    int max_flow(int s, int t) {
        // edmonds karp
        for (int flow = 0;;) {
            int res = aug(s, t);
            if (!res) return flow;
            flow += res;
            for (int j = t; j != s; j = parent[j]->pair->j) {
                parent[j]->flow += res;
                parent[j]->pair->flow -= res;
            }
        }
    }
};


typedef pair<int,int> wall;
wall walls[151111];

struct cell {
    int idx, i, j;
    int parent; // union find parent
    int label; // index in input
    bool d, r; // whether "down" or "right" is walkable
    cell() {}
    cell(int idx, int i, int j, bool d, bool r): idx(idx), i(i), j(j), parent(-1), label(-1), d(d), r(r) {}
};

#define IDX(i,j) ((i)*c+(j))

cell cells[1111111];
int r, c;

// union find
int find(int n) {
    return cells[n].parent < 0 ? n : cells[n].parent = find(cells[n].parent);
}

void onion(int a, int b) {
    a = find(a);
    b = find(b);
    if (a == b) return;
    if (cells[a].parent == cells[b].parent) cells[b].parent--;
    if (cells[a].parent > cells[b].parent) {
        cells[a].parent = b;
    } else {
        cells[b].parent = a;
    }
}

// temporary matrix
int mat[511][511];

int main() {
    int w, cost, n, comps;
    scanf("%d%d%d%d%d", &r, &c, &w, &cost, &n);

    // initialize grid
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            cells[IDX(i,j)] = cell(IDX(i,j), i, j, i != r-1, j != c-1);
        }
    }

    // collect walls
    for (int i = 0; i < w; i++) {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        x1--, y1--, x2--, y2--;
        if (x1 > x2) swap(x1, x2);
        if (y1 > y2) swap(y1, y2);
        int i1 = IDX(x1,y1);
        int i2 = IDX(x2,y2);
        walls[i] = wall(i1, i2);
        if (x1 == x2) {
            cells[i1].r = false;
        } else {
            cells[i1].d = false;
        }
    }

    // unite adjacent cells into rooms
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            int I = IDX(i,j);
            if (cells[I].d) {
                onion(IDX(i,j), IDX(i+1,j));
            }
            if (cells[I].r) {
                onion(IDX(i,j), IDX(i,j+1));
            }
        }
    }

    // initialize flow
    flow *f = new flow(n+2);
    int S = n, T = n+1, A = 0;
    // compute edges with source / sink
    for (int i = 0; i < n; i++) {
        int x, y, c1, c2;
        scanf("%d%d%d%d", &x, &y, &c1, &c2);
        x--, y--;
        cells[find(IDX(x,y))].label = i;
        int m = min(c1, c2);
        c1 -= m;
        c2 -= m;
        A += m;
        if (c1) f->add_edge(S, i, c1);
        if (c2) f->add_edge(i, T, c2);
    }
    // compute number of walls between rooms
    for (int k = 0; k < w; k++) {
        int a = cells[find(walls[k].first)].label;
        int b = cells[find(walls[k].second)].label;
        if (~a && ~b && a != b) mat[a][b]++, mat[b][a]++;
    }
    // add edges between rooms
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < i; j++) {
            if (mat[i][j]) {
                int c = mat[i][j] * cost;
                f->add_edge(i, j, c, c);
            }
        }
    }

    // flow!
    printf("%d\n", A + f->max_flow(S, T));
}