Andrewid the Android is a galaxy-known detective. Now he is preparing a defense against a possible attack by hackers on a major computer network.

In this network are n vertices, some pairs of vertices are connected by m undirected channels. It is planned to transfer q important messages via this network, the i-th of which must be sent from vertex si to vertex di via one or more channels, perhaps through some intermediate vertices.

To protect against attacks a special algorithm was developed. Unfortunately it can be applied only to the network containing directed channels. Therefore, as new channels can't be created, it was decided for each of the existing undirected channels to enable them to transmit data only in one of the two directions.

Your task is to determine whether it is possible so to choose the direction for each channel so that each of the q messages could be successfully transmitted.

Input

The first line contains three integers n, m and q (1 ≤ n, m, q ≤ 2·105) — the number of nodes, channels and important messages.

Next m lines contain two integers each, vi and ui (1 ≤ vi, ui ≤ n, vi ≠ ui), that means that between nodes vi and ui is a channel. Between a pair of nodes can exist more than one channel.

Next q lines contain two integers si and di (1 ≤ si, di ≤ n, si ≠ di) — the numbers of the nodes of the source and destination of the corresponding message.

It is not guaranteed that in it initially possible to transmit all the messages.

Output

If a solution exists, print on a single line "Yes" (without the quotes). Otherwise, print "No" (without the quotes).

Examples

Input

4 4 2
1 2
1 3
2 3
3 4
1 3
4 2


Output

Yes


Input

3 2 2
1 2
3 2
1 3
2 1


Output

No


Input

3 3 2
1 2
1 2
3 2
1 3
2 1


Output

Yes

Note

In the first sample test you can assign directions, for example, as follows: 1 → 2, 1 → 3, 3 → 2, 4 → 3. Then the path for for the first message will be 1 → 3, and for the second one — 4 → 3 → 2.

In the third sample test you can assign directions, for example, as follows: 1 → 2, 2 → 1, 2 → 3. Then the path for the first message will be 1 → 2 → 3, and for the second one — 2 → 1.
import java.io.*;
import java.util.*;


public class ProblemE {
    public static void main(String[] args) {
        int testMode = 0;
        String testInput = "7 6 2\n" +
                "1 2\n" +
                "2 3\n" +
                "3 4\n" +
                "4 5\n" +
                "5 6\n" +
                "6 7\n" +
                "2 3\n" +
                "3 5\n" +
                "1 7\n";
        /*-------------------------------------------------------------------------------------------------------*/
        FastReader in = new FastReader(testMode == 0 ? System.in : new ByteArrayInputStream(testInput.getBytes()));
        PrintWriter out = new PrintWriter(System.out);
        new ProblemSolver().solve(in, out);
        out.close();
    }
}

class ProblemSolver {
    int dfs(List<Integer>[] forest, int[] depth, int[] p, int v) throws Exception {
        int res = p[v];
        for (Integer u : forest[v]) {
            if (depth[u] < depth[v]) continue;
            int ret = dfs(forest, depth, p, u);
            if ((long) res * ret < 0) throw new Exception();
            if (ret < 0) res = Math.min(res, ret);
            else if (ret > 0) res = Math.max(res, res);
        }
        if (res > 0) res -= 1;
        else if (res < 0) res += 1;
        return res;
    }

    void solve(FastReader in, PrintWriter out) {
        int n = in.nextInt();
        int m = in.nextInt();
        int q = in.nextInt();
        List<Integer>[] graph = new List[n + 1];

        boolean ok = true;
        for (int i = 0; i < m; i++) {
            int v = in.nextInt();
            int u = in.nextInt();
            if (graph[v] == null) graph[v] = new ArrayList<>();
            if (graph[u] == null) graph[u] = new ArrayList<>();
            graph[v].add(u);
            graph[u].add(v);
            //if (i < 199995) if (v + 1 != u) ok = false;
            //if (i >= 199995 && ok) out.println(v + " " + u);
        }

        Edge[] bridges = new BridgesInUndirGraph(graph).getBridges();
        HashSet<Edge> bridgesTest = new HashSet<>();
        for (Edge e : bridges) {
            bridgesTest.add(e);
            bridgesTest.add(new Edge(e.to, e.from));
        }

        boolean[] vis = new boolean[n + 1];
        int[] queue = new int[n + 1];
        int[] verticesRemap = new int[n + 1];
        int next_w = 1;
        List<Integer>[] forest = new List[n + 1];
        List<Integer> roots = new ArrayList<>();
        for (int i = 1; i <= n; i++) {
            if (vis[i]) continue;
            int last = 1;
            queue[0] = i;
            vis[i] = true;
            verticesRemap[i] = next_w++;
            forest[verticesRemap[i]] = new ArrayList<>();
            roots.add(verticesRemap[i]);
            for (int k = 0; k < last; k++) {
                int v = queue[k];
                for (Integer u : graph[v]) {
                    if (!vis[u]) {
                        queue[last++] = u;
                        vis[u] = true;
                        verticesRemap[u] = verticesRemap[v];
                    }
                    if (bridgesTest.contains(new Edge(v, u))) {
                        bridgesTest.remove(new Edge(v, u));
                        bridgesTest.remove(new Edge(u, v));
                        verticesRemap[u] = next_w++;
                        forest[verticesRemap[u]] = new ArrayList<>();
                        forest[verticesRemap[u]].add(verticesRemap[v]);
                        forest[verticesRemap[v]].add(verticesRemap[u]);
                    }
                }
            }
        }

        int[] depth = new int[forest.length];
        Arrays.fill(depth, -1);
        for (int i = 0; i < roots.size(); i++) {
            int r = roots.get(i);
            int d = 0;
            int last = 0;
            queue[last++] = r;
            depth[r] = d;
            for (int k = 0; k < last; k++) {
                int v = queue[k];
                for (Integer u : forest[v]) {
                    if (depth[u] != -1) continue;
                    depth[u] = depth[v] + 1;
                    queue[last++] = u;
                }
            }
        }

        LcaInForest lca = new LcaInForest(forest, roots.stream().mapToInt(i -> i).toArray());
        int[] p = new int[forest.length];
        for (int i = 0; i < q; i++) {
            int a = in.nextInt();
            int b = in.nextInt();
            int v = verticesRemap[a];
            int u = verticesRemap[b];
            int ancestor = lca.query(v, u);
            if (ancestor == -1) {
                out.println("No");
                //if (ok && m == 199999) out.print("q1: " + a + " " + b);
                return;
            }
            int lv = depth[v] - depth[ancestor];
            int lu = depth[ancestor] - depth[u];
            if ((long) lv * p[v] < 0 || (long) lu * p[u] < 0) {
                out.println("No");
                return;
            }
            p[v] = lv < 0 ? Math.min(p[v], lv) : Math.max(p[v], lv);
            p[u] = lu < 0 ? Math.min(p[u], lu) : Math.max(p[u], lu);
        }

        for (int i = 0; i < roots.size(); i++) {
            int r = roots.get(i);
            try {
                dfs(forest, depth, p, r);
            } catch (Exception e) {
                out.println("No");
                //if (ok && m == 199999) out.print("q3: dfs");
                return;
            }
        }
        out.println("Yes");
    }
}

class LcaInForest {
    // The algorithm has preprocessing time O(N) and query time O(logN)
    // It reduces the problem to Range Minimum query and solves the latter problem
    // with segment trees
    // query method returns LCA of given nodes or -1 if nodes have no ancestor

    List<Integer>[] forest;
    int[] eulerTour;
    int[] nodeOrder;
    int[] nodeDepth;
    int[] segmentMin;
    int n;

    public LcaInForest(List<Integer>[] forest, int[] roots) {
        this.forest = forest;
        n = forest.length;
        eulerTour = new int[n * 2 + roots.length - 1];
        nodeOrder = new int[n + 1];
        nodeDepth = new int[n + 1];
        segmentMin = new int[eulerTour.length * 4];
        Arrays.fill(eulerTour, n);
        Arrays.fill(nodeOrder, -1);
        nodeDepth[n] = -1;
        int order = 0;
        for (int i = 0; i < roots.length; i++) {
            order = dfs(roots[i], order + (i != 0 ? 1 : 0), 0) + 1;
        }
        buildSegmentTree(0, 0, eulerTour.length - 1);
    }

    int dfs(int node, int order, int depth) {
        eulerTour[order] = node;
        nodeOrder[node] = order;
        nodeDepth[node] = depth;
        for (Integer child : forest[node]) {
            if (nodeOrder[child] == -1) {
                order = dfs(child, order + 1, depth + 1) + 1;
                eulerTour[order] = node;
            }
        }
        return order;
    }

    int buildSegmentTree(int idx, int ltSegmentBoundary, int rtSegmentBoundary) {
        if (ltSegmentBoundary == rtSegmentBoundary)
            return segmentMin[idx] = ltSegmentBoundary;
        int mid = (ltSegmentBoundary + rtSegmentBoundary) / 2;
        int ltMin = buildSegmentTree(idx * 2 + 1, ltSegmentBoundary, mid);
        int rtMin = buildSegmentTree(idx * 2 + 2, mid + 1, rtSegmentBoundary);
        return segmentMin[idx] = nodeDepth[eulerTour[ltMin]] < nodeDepth[eulerTour[rtMin]] ? ltMin : rtMin;
    }

    int findMin(int ltQueryBoundary, int rtQueryBoundary, int idx, int ltSegmentBoundary, int rtSegmentBoundary) {
        if (ltQueryBoundary <= ltSegmentBoundary && rtSegmentBoundary <= rtQueryBoundary)
            return segmentMin[idx];
        if (ltQueryBoundary > rtSegmentBoundary || rtQueryBoundary < ltSegmentBoundary)
            return -1;
        int mid = (ltSegmentBoundary + rtSegmentBoundary) / 2;
        int ltMin = findMin(ltQueryBoundary, rtQueryBoundary, idx * 2 + 1, ltSegmentBoundary, mid);
        int rtMin = findMin(ltQueryBoundary, rtQueryBoundary, idx * 2 + 2, mid + 1, rtSegmentBoundary);
        if (ltMin == -1 && rtMin == -1)
            return -1;
        else if (ltMin == -1)
            return rtMin;
        else if (rtMin == -1)
            return ltMin;
        return nodeDepth[eulerTour[ltMin]] < nodeDepth[eulerTour[rtMin]] ? ltMin : rtMin;
    }

    int query(int v, int u) {
        int ret = findMin(Math.min(nodeOrder[v], nodeOrder[u]), Math.max(nodeOrder[v], nodeOrder[u]), 0, 0, eulerTour.length - 1);
        return ret == -1 || eulerTour[ret] == n ? -1 : eulerTour[ret];
    }
}

class BridgesInUndirGraph {
    List<Integer>[] graph;
    int[] enter;
    int[] low;
    List<Edge> edges;

    public BridgesInUndirGraph(List<Integer>[] graph) {
        this.graph = graph;
        enter = new int[graph.length];
        low = new int[graph.length];
        edges = new ArrayList<>();
        Arrays.fill(enter, -1);
        int time = -1;
        for (int v = 0; v < graph.length; v++) {
            if (graph[v] == null || enter[v] != -1) continue;
            time = dfs(v, -1, time + 1);
        }
    }

    int dfs(int v, int parent, int time) {
        enter[v] = time;
        low[v] = time;
        int edgeToParentCnt = 0;
        for (Integer u : graph[v]) {
            if (enter[u] == -1) {
                edges.add(new Edge(v, u));
                time = dfs(u, v, time + 1);
                low[v] = Math.min(low[v], low[u]);
            } else {
                if (u != parent || edgeToParentCnt > 0)
                    low[v] = Math.min(low[v], enter[u]);
                else
                    edgeToParentCnt++;
            }
        }
        return time;
    }

    Edge[] getBridges() {
        ArrayList<Edge> bridges = new ArrayList<>();
        for (Edge edge : edges) {
            int u = edge.to;
            if (low[u] == enter[u]) bridges.add(edge);
        }
        return (Edge[]) bridges.toArray(new Edge[0]);
    }
}

class Edge {
    int from;
    int to;

    public Edge(int from, int to) {
        this.from = from;
        this.to = to;
    }

    public int hashCode() {
        return (to * 31) ^ from;
    }

    public boolean equals(Object obj) {
        Edge that = (Edge) obj;
        return this.from == that.from && this.to == that.to;
    }
}

class FastReader extends BufferedReader {
    private StringTokenizer st;

    public FastReader(InputStream is) {
        super(new InputStreamReader(is));
    }

    public String nextToken() {
        try {
            while (st == null || !st.hasMoreElements()) {
                st = new StringTokenizer(readLine());
            }
            return st.nextToken();
        } catch (IOException e) {
            return null;
        }
    }

    public int nextInt() {
        return Integer.parseInt(nextToken());
    }

    public long nextLong() {
        return Long.parseLong(nextToken());
    }

    public int[] nextArrayInt(int size) {
        int[] ret = new int[size];
        for (int i = 0; i < size; i++) {
            ret[i] = nextInt();
        }
        return ret;
    }
}