The new academic year has started, and Berland's university has n first-year students. They are divided into k academic groups, however, some of the groups might be empty. Among the students, there are m pairs of acquaintances, and each acquaintance pair might be both in a common group or be in two different groups.

Alice is the curator of the first years, she wants to host an entertaining game to make everyone know each other. To do that, she will select two different academic groups and then divide the students of those groups into two teams. The game requires that there are no acquaintance pairs inside each of the teams.

Alice wonders how many pairs of groups she can select, such that it'll be possible to play a game after that. All students of the two selected groups must take part in the game.

Please note, that the teams Alice will form for the game don't need to coincide with groups the students learn in. Moreover, teams may have different sizes (or even be empty).

Input

The first line contains three integers n, m and k (1 ≤ n ≤ 500 000; 0 ≤ m ≤ 500 000; 2 ≤ k ≤ 500 000) — the number of students, the number of pairs of acquaintances and the number of groups respectively.

The second line contains n integers c_1, c_2, ..., c_n (1 ≤ c_i ≤ k), where c_i equals to the group number of the i-th student.

Next m lines follow. The i-th of them contains two integers a_i and b_i (1 ≤ a_i, b_i ≤ n), denoting that students a_i and b_i are acquaintances. It's guaranteed, that a_i ≠ b_i, and that no (unordered) pair is mentioned more than once.

Output

Print a single integer — the number of ways to choose two different groups such that it's possible to select two teams to play the game.

Examples

Input


6 8 3
1 1 2 2 3 3
1 3
1 5
1 6
2 5
2 6
3 4
3 5
5 6


Output


2


Input


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


Output


3


Input


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


Output


0


Input


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


Output


0

Note

The acquaintances graph for the first example is shown in the picture below (next to each student there is their group number written).

<image>

In that test we can select the following groups:

  * Select the first and the second groups. For instance, one team can be formed from students 1 and 4, while other team can be formed from students 2 and 3. 
  * Select the second and the third group. For instance, one team can be formed 3 and 6, while other team can be formed from students 4 and 5. 
  * We can't select the first and the third group, because there is no way to form the teams for the game. 



In the second example, we can select any group pair. Please note, that even though the third group has no students, we still can select it (with some other group) for the game.
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.io.IOException;
import java.util.Deque;
import java.util.ArrayList;
import java.io.UncheckedIOException;
import java.util.List;
import java.util.Map;
import java.io.Closeable;
import java.util.Map.Entry;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.ArrayDeque;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(null, new TaskAdapter(), "", 1 << 29);
        thread.start();
        thread.join();
    }

    static class TaskAdapter implements Runnable {
        @Override
        public void run() {
            InputStream inputStream = System.in;
            OutputStream outputStream = System.out;
            FastInput in = new FastInput(inputStream);
            FastOutput out = new FastOutput(outputStream);
            CTeamBuilding solver = new CTeamBuilding();
            solver.solve(1, in, out);
            out.close();
        }
    }

    static class CTeamBuilding {
        public void solve(int testNumber, FastInput in, FastOutput out) {
            int n = in.readInt();
            int m = in.readInt();
            int k = in.readInt();

            int[] g = new int[n];
            in.populate(g);
            Map<Long, List<int[]>> edges = new HashMap<>();
            UndoStack stack = new UndoStack(m);
            UndoXorDSU dsu = new UndoXorDSU(n);
            dsu.init();
            boolean[] valid = new boolean[k + 1];
            Arrays.fill(valid, true);
            valid[0] = false;
            for (int i = 0; i < m; i++) {
                int u = in.readInt() - 1;
                int v = in.readInt() - 1;
                if (g[u] == g[v]) {
                    if (dsu.find(u) == dsu.find(v)) {
                        if (dsu.xor(u, v) != 1) {
                            valid[g[u]] = false;
                        }
                    } else {
                        stack.push(dsu.merge(u, v, 1));
                    }
                } else {
                    int[] e = new int[]{u, v};
                    long key = merge(g[u], g[v]);
                    edges.computeIfAbsent(key, x -> new ArrayList<>()).add(e);
                }
            }

            long validCnt = 0;
            for (int i = 1; i <= k; i++) {
                if (valid[i]) {
                    validCnt++;
                }
            }
            long ans = validCnt * (validCnt - 1) / 2;

            for (Map.Entry<Long, List<int[]>> entry : edges.entrySet()) {
                int g1 = DigitUtils.highBit(entry.getKey());
                int g2 = DigitUtils.lowBit(entry.getKey());
                if (!(valid[g1] && valid[g2])) {
                    continue;
                }
                int size = stack.size();
                boolean possible = true;
                for (int[] e : entry.getValue()) {
                    int u = e[0];
                    int v = e[1];
                    if (dsu.find(u) == dsu.find(v)) {
                        if (dsu.xor(u, v) == 0) {
                            possible = false;
                        }
                    } else {
                        stack.push(dsu.merge(u, v, 1));
                    }
                }
                if (!possible) {
                    ans--;
                }
                while (stack.size() > size) {
                    stack.pop();
                }
            }

            out.println(ans);
        }

        public long merge(int a, int b) {
            if (a > b) {
                int tmp = a;
                a = b;
                b = tmp;
            }
            return DigitUtils.asLong(a, b);
        }

    }

    static interface UndoOperation {
        void apply();

        void undo();

    }

    static abstract class CommutativeUndoOperation implements UndoOperation {
    }

    static class UndoStack {
        private Deque<UndoOperation> dq;

        public UndoStack(int size) {
            dq = new ArrayDeque<>(size);
        }

        public void push(UndoOperation op) {
            dq.addLast(op);
            op.apply();
        }

        public void pop() {
            dq.removeLast().undo();
        }

        public int size() {
            return dq.size();
        }

    }

    static class UndoXorDSU {
        int[] rank;
        int[] p;
        long[] xor;

        public UndoXorDSU(int n) {
            rank = new int[n];
            p = new int[n];
            xor = new long[n];
        }

        public void init() {
            Arrays.fill(rank, 1);
            Arrays.fill(p, -1);
            Arrays.fill(xor, 0);
        }

        public int find(int x) {
            while (p[x] != -1) {
                x = p[x];
            }
            return x;
        }

        public long xorToRoot(int x) {
            long ans = 0;
            while (p[x] != -1) {
                ans ^= xor[x];
                x = p[x];
            }
            return ans;
        }

        public long xor(int a, int b) {
            return xorToRoot(a) ^ xorToRoot(b);
        }

        public CommutativeUndoOperation merge(int a, int b, long d) {
            return new CommutativeUndoOperation() {
                int x, y;

                public void apply() {
                    x = find(a);
                    y = find(b);
                    long delta = xorToRoot(a) ^ xorToRoot(b) ^ d;
                    if (x == y) {
                        return;
                    }
                    if (rank[x] < rank[y]) {
                        int tmp = x;
                        x = y;
                        y = tmp;
                    }
                    p[y] = x;
                    xor[y] = delta;
                    rank[x] += rank[y];
                }


                public void undo() {
                    int cur = y;
                    while (p[cur] != -1) {
                        cur = p[cur];
                        rank[cur] -= rank[y];
                    }
                    p[y] = -1;
                    xor[y] = 0;
                }
            };
        }

    }

    static class FastOutput implements AutoCloseable, Closeable, Appendable {
        private static final int THRESHOLD = 1 << 13;
        private final Writer os;
        private StringBuilder cache = new StringBuilder(THRESHOLD * 2);

        public FastOutput append(CharSequence csq) {
            cache.append(csq);
            return this;
        }

        public FastOutput append(CharSequence csq, int start, int end) {
            cache.append(csq, start, end);
            return this;
        }

        private void afterWrite() {
            if (cache.length() < THRESHOLD) {
                return;
            }
            flush();
        }

        public FastOutput(Writer os) {
            this.os = os;
        }

        public FastOutput(OutputStream os) {
            this(new OutputStreamWriter(os));
        }

        public FastOutput append(char c) {
            cache.append(c);
            afterWrite();
            return this;
        }

        public FastOutput append(long c) {
            cache.append(c);
            afterWrite();
            return this;
        }

        public FastOutput append(String c) {
            cache.append(c);
            afterWrite();
            return this;
        }

        public FastOutput println(long c) {
            return append(c).println();
        }

        public FastOutput println() {
            return append(System.lineSeparator());
        }

        public FastOutput flush() {
            try {
                os.append(cache);
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
            return this;
        }

        public void close() {
            flush();
            try {
                os.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        public String toString() {
            return cache.toString();
        }

    }

    static class FastInput {
        private final InputStream is;
        private byte[] buf = new byte[1 << 13];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastInput(InputStream is) {
            this.is = is;
        }

        public void populate(int[] data) {
            for (int i = 0; i < data.length; i++) {
                data[i] = readInt();
            }
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    bufLen = -1;
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

    }

    static class DigitUtils {
        private static long LONG_TO_INT_MASK = (1L << 32) - 1;

        private DigitUtils() {
        }

        public static long asLong(int high, int low) {
            return (((long) high) << 32) | (((long) low) & LONG_TO_INT_MASK);
        }

        public static int highBit(long x) {
            return (int) (x >> 32);
        }

        public static int lowBit(long x) {
            return (int) x;
        }

    }
}

