#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/priority_queue.hpp>
//#pragma GCC optimize("O3")
//#pragma GCC target("sse4")
//#pragma GCC target("avx2")
 
#define deb(x) cout << #x << " = " << x << "\n"
#define all(x) (x).begin(), (x).end()
#define len(x) (int) x.size()
#define lsb(x) (x) & -(x)
#define l(x) (x << 1) + 1
#define r(x) (x << 1) + 2
#define v(x) (int)(x - 'a')
 
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define lb lower_bound
#define ub upper_bound
 
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ld, ld> pld;
typedef pair <ll, ll> pll;
 
template <class T1, class T2 = less <T1>> using pb_heap = __gnu_pbds::priority_queue <T1, T2, binary_heap_tag>;
template <class T1, class T2 = null_type, class T3 = less <T1>> using pb_map = tree <T1, T2, T3, rb_tree_tag, tree_order_statistics_node_update>;
template <class T1, class T2 = null_type, class T3 = hash <T1>> using pb_umap = gp_hash_table <T1, T2, T3>;
template <class T1, class T2, class T3 = hash <T1>> using umap = unordered_map <T1, T2, T3>;
template <class T> using uset = unordered_set <T>;
template <class T> using vec = vector <T>;
 
const ll infll = numeric_limits <ll>::max() >> 1;
const int inf = numeric_limits <int>::max() >> 1;
const int N = 4e5 + 5;
const int M = 25e5 + 1;
int p, n, lim, m, cur, cnt;
 
pii ival[N];
vec <int> ts;
 
struct Node {
    int ind;
};
Node nodex[N << 2];
 
struct Graph {
    int scc[N << 1];
    int ord[N << 1];
    bitset <M> vis;
    vec <int> adj[M];
    // vec <int> rev[M];
} graph;
 
void add_edge(int u, int v) {
    graph.adj[u].pb(v);
    if(n < 400000)
    // graph.rev[v].pb(u);
    cnt++;
}
 
void build(int id, int l, int r, Node node[]) {
    node[id].ind = ++cur;
    if(l == r) {
        return;
    }
    int q = l + r >> 1;
    build(l(id), l, q, node);
    build(r(id), q + 1, r, node);
}
 
void update(int id, int l, int r, int lx, int rx, int x, Node node[]) {
    if(l > r) {
        return;
    }
    if(lx == l && rx == r) {
        add_edge(x, node[id].ind);
        return;
    }
    int q = lx + rx >> 1;
    if(l <= q) {
        update(l(id), l, min(q, r), lx, q, x, node);
    }
    if(r > q) {
        update(r(id), max(q + 1, l), r, q + 1, rx, x, node);
    }
}
 
void update(int id, int i, int x, int lx, int rx, Node node[]) {
    add_edge(node[id].ind, x);
    if(lx == rx) {
        return;
    }
    int q = lx + rx >> 1;
    if(i <= q) {
        update(l(id), i, x, lx, q, node);
    } else {
        update(r(id), i, x, q + 1, rx, node);
    }
}
 
void input() {
    cin >> p >> n >> lim >> m;
    for(int i = 1; i <= p; ++i) {
        int u; cin >> u;
        int v; cin >> v;
        add_edge(r(u), l(v));
        add_edge(r(v), l(u));
    }
    for(int i = 1; i <= n; ++i) {
        cin >> ival[i].xx;
        cin >> ival[i].yy;
    }
    for(int i = 1; i <= m; ++i) {
        int u; cin >> u;
        int v; cin >> v;
        add_edge(l(u), r(v));
        add_edge(l(v), r(u));
    }
}
 
void topsort(int u) {
    static int t = 0;
    graph.vis[u] = 1;
    for(int v: graph.adj[u]) {
        if(!graph.vis[v]) {
            topsort(v);
        }
    }
    if(u < (N << 1))
    graph.ord[u] = ++t;
    ts.pb(u);
}
 
void visit(int u, int scc) {
    graph.vis[u] = 1;
    if(u < (N << 1))
    graph.scc[u] = scc;
    // for(int v: graph.rev[u]) {
    //     if(!graph.vis[v]) {
    //         visit(v, scc);
    //     }
    // }
}
 
int intersect(vec <int> &answer) {
    pii res = {1, lim};
    for(int e: answer) {
        res.xx = max(res.xx, ival[e].xx);
        res.yy = min(res.yy, ival[e].yy);
    }
    return res.xx;
}
 
void solve() {
    cur = r(n) + 1;
    build(0, 1, lim, nodex);
    for(int i = 1; i <= n; ++i) {
        update(0, 1, ival[i].xx - 1, 1, lim, l(i), nodex);
    }
    for(int i = 1; i <= n; ++i) {
        update(0, ival[i].yy, r(i), 1, lim, nodex);
    }
    build(0, 1, lim, nodex);
    for(int i = 1; i <= n; ++i) {
        update(0, ival[i].yy + 1, lim, 1, lim, l(i), nodex);
    }
    for(int i = 1; i <= n; ++i) {
        update(0, ival[i].xx, r(i), 1, lim, nodex);
    }
    for(int i = l(1); i <= r(n); ++i) {
        if(!graph.vis[i]) {
            topsort(i);
        }
    }
    graph.vis = 0;
    int ind = 0;
    reverse(all(ts));
    for(int i: ts) {
        if(!graph.vis[i]) {
            visit(i, ind++);
        }
    }
    for(int i = 1; i <= n; ++i) {
        if(graph.scc[l(i)] == graph.scc[r(i)]) {
            cout << "-1\n";
            return;
        }
    }
    vec <int> answer;
    for(int i = 1; i <= n; ++i) {
        if(graph.ord[l(i)] < graph.ord[r(i)]) {
            answer.pb(i);
        }
    }
    if(n == 400000) {
        cout << cnt << "\n";
    }
    cout << len(answer) << " " << intersect(answer) << "\n";
    for(int e: answer) {
        cout << e << " ";
    }
    cout << "\n";
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    input();
    solve();
}