Problem:
Score : 900 points

Problem Statement

We have a connected undirected graph with N vertices and M edges.
Edge i in this graph (1 \leq i \leq M) connects Vertex U_i and Vertex V_i bidirectionally.
We are additionally given N integers D_1, D_2, ..., D_N.

Determine whether the conditions below can be satisfied by assigning a color - white or black - to each vertex and an integer weight between 1 and 10^9 (inclusive) to each edge in this graph.
If the answer is yes, find one such assignment of colors and integers, too.

There is at least one vertex assigned white and at least one vertex assigned black.

For each vertex v (1 \leq v \leq N), the following holds.

The minimum cost to travel from Vertex v to a vertex whose color assigned is different from that of Vertex v by traversing the edges is equal to D_v.

Here, the cost of traversing the edges is the sum of the weights of the edges traversed.

Constraints

2 \leq N \leq 100,000

1 \leq M \leq 200,000

1 \leq D_i \leq 10^9

1 \leq U_i, V_i \leq N

The given graph is connected and has no self-loops or multiple edges.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N M
D_1 D_2 ... D_N
U_1 V_1
U_2 V_2
\vdots
U_M V_M

Output

If there is no assignment satisfying the conditions, print a single line containing -1.

If such an assignment exists, print one such assignment in the following format:

S
C_1
C_2
\vdots
C_M

Here,

the first line should contain the string S of length N. Its i-th character (1 \leq i \leq N) should be W if Vertex i is assigned white and B if it is assigned black.

The (i + 1)-th line (1 \leq i \leq M) should contain the integer weight C_i assigned to Edge i.

Sample Input 1

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

Sample Output 1

BWWBB
4
3
1
5
2

Assume that we assign the colors and integers as the sample output, and let us consider Vertex 5, for example. To travel from Vertex 5, which is assigned black, to a vertex that is assigned white with the minimum cost, we should make these moves: Vertex 5 \to Vertex 4 \to Vertex 2. The total cost of these moves is 7, which satisfies the condition. We can also verify that the condition is satisfied for other vertices.

Sample Input 2

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

Sample Output 2

-1

Sample Input 3

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

Sample Output 3

BBBW
1
1
1
2
1
1

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

/* preprocessor start */
#ifdef LOCAL
    #define _GLIBCXX_DEBUG  // gcc
    #define _LIBCPP_DEBUG 0 // clang
    #define __clock__
#else
    #pragma GCC optimize("Ofast")
    // #define _GLIBCXX_DEBUG
    // #define _LIBCPP_DEBUG 0
    // #define NDEBUG
#endif
// #define __buffer_check__
#define __precision__ 10
#define iostream_untie true
#define debug_stream std::cerr
#include <algorithm>
#include <bitset>
#include <cassert>
#include <chrono>
#include <complex>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <valarray>
#define __all(v) std::begin(v), std::end(v)
#define __rall(v) std::rbegin(v), std::rend(v)
#define __popcount(n) __builtin_popcountll(n)
#define __clz32(n) __builtin_clz(n)
#define __clz64(n) __builtin_clzll(n)
#define __ctz32(n) __builtin_ctz(n)
#define __ctz64(n) __builtin_ctzll(n)
/* preprocessor end */

namespace setting
{
    using namespace std::chrono;
    system_clock::time_point start_time, end_time;
    long long get_elapsed_time() { end_time = system_clock::now(); return duration_cast<milliseconds>(end_time - start_time).count(); }
    void print_elapsed_time() { debug_stream << "\n----- Exec time : " << get_elapsed_time() << " ms -----\n"; }
    void buffer_check() { char bufc; if(std::cin >> bufc) debug_stream << "\n\033[1;35mwarning\033[0m: buffer not empty.\n"; }
    struct setupper
    {
        setupper()
        {
            using namespace std;
            if(iostream_untie) ios::sync_with_stdio(false), cin.tie(nullptr);
            cout << fixed << setprecision(__precision__);
    #ifdef stderr_path
            if(freopen(stderr_path, "a", stderr)) cerr << fixed << setprecision(__precision__);
    #endif
    #ifdef LOCAL
            debug_stream << "\n----- stderr at LOCAL -----\n\n";
    #endif
    #ifdef __buffer_check__
            atexit(buffer_check);
    #endif
    #ifdef __clock__
            start_time = system_clock::now();
            atexit(print_elapsed_time);
    #endif
        }
    } __setupper; // struct setupper
} // namespace setting
#ifdef __clock__
class
{
    std::chrono::system_clock::time_point built_pt, last_pt; int built_ln, last_ln;
    std::string built_func, last_func; bool is_built = false;
public:
    void build(int crt_ln, const std::string &crt_func)
    {
        is_built = true, last_pt = built_pt = std::chrono::system_clock::now(), last_ln = built_ln = crt_ln, last_func = built_func = crt_func;
    }
    void set(int crt_ln, const std::string &crt_func)
    {
        if(is_built) last_pt = std::chrono::system_clock::now(), last_ln = crt_ln, last_func = crt_func;
        else debug_stream << "[ " << crt_ln << " : " << crt_func << " ] " << "myclock_t::set failed (yet to be built!)\n";
    }
    void get(int crt_ln, const std::string &crt_func)
    {
        if(is_built)
        {
            std::chrono::system_clock::time_point crt_pt(std::chrono::system_clock::now());
            long long diff = std::chrono::duration_cast<std::chrono::milliseconds>(crt_pt - last_pt).count();
            debug_stream << diff << " ms elapsed from" << " [ " << last_ln << " : " << last_func << " ]";
            if(last_ln == built_ln) debug_stream << " (when built)";
            debug_stream << " to" << " [ " << crt_ln << " : " << crt_func << " ]" << "\n";
            last_pt = built_pt, last_ln = built_ln, last_func = built_func;
        }
        else
        {
            debug_stream << "[ " << crt_ln << " : " << crt_func << " ] " << "myclock_t::get failed (yet to be built!)\n";
        }
    }
} myclock; // unnamed class
    #define build_clock() myclock.build(__LINE__, __func__)
    #define set_clock() myclock.set(__LINE__, __func__)
    #define get_clock() myclock.get(__LINE__, __func__)
#else
    #define build_clock() ((void)0)
    #define set_clock() ((void)0)
    #define get_clock() ((void)0)
#endif

namespace std
{
    // hash
    template <class T> size_t hash_combine(size_t seed, T const &key) { return seed ^ (hash<T>()(key) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); }
    template <class T, class U> struct hash<pair<T, U>> { size_t operator()(pair<T, U> const &pr) const { return hash_combine(hash_combine(0, pr.first), pr.second); } };
    template <class tuple_t, size_t index = tuple_size<tuple_t>::value - 1> struct tuple_hash_calc { static size_t apply(size_t seed, tuple_t const &t) { return hash_combine(tuple_hash_calc<tuple_t, index - 1>::apply(seed, t), get<index>(t)); } };
    template <class tuple_t> struct tuple_hash_calc<tuple_t, 0> { static size_t apply(size_t seed, tuple_t const &t) { return hash_combine(seed, get<0>(t)); } };
    template <class... T> struct hash<tuple<T...>> { size_t operator()(tuple<T...> const &t) const { return tuple_hash_calc<tuple<T...>>::apply(0, t); } };
    // iostream
    template <class T, class U> istream &operator>>(istream &is, pair<T, U> &p) { return is >> p.first >> p.second; }
    template <class T, class U> ostream &operator<<(ostream &os, const pair<T, U> &p) { return os << p.first << ' ' << p.second; }
    template <class tuple_t, size_t index> struct tupleis { static istream &apply(istream &is, tuple_t &t) { tupleis<tuple_t, index - 1>::apply(is, t); return is >> get<index>(t); } };
    template <class tuple_t> struct tupleis<tuple_t, SIZE_MAX> { static istream &apply(istream &is, tuple_t &t) { return is; } };
    template <class... T> istream &operator>>(istream &is, tuple<T...> &t) { return tupleis<tuple<T...>, tuple_size<tuple<T...>>::value - 1>::apply(is, t); }
    template <> istream &operator>>(istream &is, tuple<> &t) { return is; }
    template <class tuple_t, size_t index> struct tupleos { static ostream &apply(ostream &os, const tuple_t &t) { tupleos<tuple_t, index - 1>::apply(os, t); return os << ' ' << get<index>(t); } };
    template <class tuple_t> struct tupleos<tuple_t, 0> { static ostream &apply(ostream &os, const tuple_t &t) { return os << get<0>(t); } };
    template <class... T> ostream &operator<<(ostream &os, const tuple<T...> &t) { return tupleos<tuple<T...>, tuple_size<tuple<T...>>::value - 1>::apply(os, t); }
    template <> ostream &operator<<(ostream &os, const tuple<> &t) { return os; }
    template <class Container, typename Value = typename Container::value_type, enable_if_t<!is_same<decay_t<Container>, string>::value, nullptr_t> = nullptr>
    istream& operator>>(istream& is, Container &cont) { for(auto&& e : cont) is >> e; return is; }
    template <class Container, typename Value = typename Container::value_type, enable_if_t<!is_same<decay_t<Container>, string>::value, nullptr_t> = nullptr>
    ostream& operator<<(ostream& os, const Container &cont) { bool flag = 1; for(auto&& e : cont) flag ? flag = 0 : (os << ' ', 0), os << e; return os; }
} // namespace std

/* dump definition start */
#ifdef LOCAL
    #define dump(...) debug_stream << "[ " << __LINE__ << " : " << __FUNCTION__ << " ]\n", dump_func(#__VA_ARGS__, __VA_ARGS__)
    template <class T> void dump_func(const char *ptr, const T &x)
    {
        debug_stream << '\t';
        for(char c = *ptr; c != '\0'; c = *++ptr) if(c != ' ' && c != '\t') debug_stream << c;
        debug_stream << " : " << x << '\n';
    }
    template <class T, class... rest_t> void dump_func(const char *ptr, const T &x, rest_t... rest)
    {
        debug_stream << '\t';
        for(char c = *ptr; c != ','; c = *++ptr) if(c != ' ' && c != '\t') debug_stream << c;
        debug_stream << " : " << x << ",\n"; dump_func(++ptr, rest...);
    }
#else
    #define dump(...) ((void)0)
#endif
/* dump definition end */

/* function utility start */
template <class T, class... types> T read(types... args) noexcept { T obj(args...); std::cin >> obj; return obj; }
#define input(type, var, ...) type var{read<type>(__VA_ARGS__)}
// substitute y for x if x > y.
template <class T> inline bool sbmin(T &x, const T &y) { return x > y ? x = y, true : false; }
// substitute y for x if x < y.
template <class T> inline bool sbmax(T &x, const T &y) { return x < y ? x = y, true : false; }
// binary search on discrete range.
template <class iter_type, class pred_type>
iter_type binary(iter_type __ok, iter_type __ng, pred_type pred)
{
    std::ptrdiff_t dist(__ng - __ok);
    while(std::abs(dist) > 1)
    {
        iter_type mid(__ok + dist / 2);
        if(pred(mid)) __ok = mid, dist -= dist / 2;
        else __ng = mid, dist /= 2;
    }
    return __ok;
}
// binary search on real numbers.
template <class pred_type>
long double binary(long double __ok, long double __ng, const long double eps, pred_type pred)
{
    while(std::abs(__ok - __ng) > eps)
    {
        long double mid{(__ok + __ng) / 2};
        (pred(mid) ? __ok : __ng) = mid;
    }
    return __ok;
}
// reset all bits.
template <class A> void reset(A &array) { memset(array, 0, sizeof(array)); }
// be careful that val is type-sensitive.
template <class T, class A, size_t N> void init(A (&array)[N], const T &val) { std::fill((T*)array, (T*)(array + N), val); }
/* functon utility end */

/* using alias start */
using namespace std;
using i32 = int_least32_t; using i64 = int_least64_t; using u32 = uint_least32_t; using u64 = uint_least64_t;
using pii = pair<i32, i32>; using pll = pair<i64, i64>;
template <class T, class Comp = less<T>> using heap = priority_queue<T, vector<T>, Comp>;
template <class T> using hashset = unordered_set<T>;
template <class Key, class Value> using hashmap = unordered_map<Key, Value>;
/* using alias end */

/* library start */

// #line 2 "Union_find.hpp"
#ifndef Union_find_hpp
#define Union_find_hpp
#include <cassert>
#include <cstdint>
#include <numeric>
#include <vector>

class union_find
{
    const size_t n;
    std::vector<int> link;
    bool *const cyc, *const clr, *const flip;
    size_t comp, isol;
    bool bipart;

public:
    explicit union_find(const size_t _n) : n(_n), link(n, -1), cyc(new bool[n]{}), clr(new bool[n]{}), flip(new bool[n]{}), comp(n), isol(n), bipart(true) {}
    ~union_find() { delete[] cyc; delete[] clr; delete[] flip; }

    size_t find(const size_t x)
    {
        assert(x < n);
        if(link[x] < 0) return x;
        const size_t r = find(link[x]);
        if(flip[link[x]]) clr[x] = !clr[x], flip[x] = !flip[x];
        return link[x] = r;
    }

    size_t size() const { return n; }
    size_t size(const size_t x) { return -link[find(x)]; }

    size_t count() const { return comp; }

    size_t isolated() const { return isol; }

    bool color(const size_t x) { return find(x), clr[x]; }

    bool cyclic(const size_t x) { return cyc[find(x)]; }

    bool same(const size_t x, const size_t y) { return find(x) == find(y); }

    bool bipartite() const { return bipart; }

    bool unite(size_t x, size_t y)
    {
        const size_t _x = find(x), _y = find(y);
        const bool f = clr[x] == clr[y];
        x = _x, y = _y;
        if(x == y)
        {
            bipart &= !f;
            cyc[x] = true;
            return false;
        }
        if(link[x] > link[y]) std::swap(x, y);
        if(link[x] == -1) --isol;
        if(link[y] == -1) --isol;
        link[x] += link[y], link[y] = x;
        cyc[x] = cyc[x] || cyc[y];
        if(f) clr[y] = !clr[y], flip[y] = !flip[y];
        --comp;
        return true;
    }
}; // class union_find

#endif

/* library end */

/* The main code follows. */


struct solver
{
    int n;
    int m;
    vector<int> d;
    vector<vector<pii>> g;
    vector<int> w;
    string co;
    solver(): n(read<int>()),m(read<int>()),d(read<vector<int>>(n)),g(n),w(m,1e9),co(n,'-')
    {
        union_find uf(n);

        for(int i=0; i<m; ++i)
        {
            int u,v; cin>>u>>v;
            u--,v--;
            g[u].emplace_back(v,i);
            g[v].emplace_back(u,i);
        }

        vector<int> vs(n);
        iota(__all(vs),0);
        sort(__all(vs),[&](int x,int y){return d[x]<d[y];});

        int root=d.front();

        // check
        {
            auto itr=min_element(__all(d));
            root=itr-begin(d);
            bool ok=false;
            for(auto i=d.begin(); i!=d.end(); i++)
            {
                if(i==itr)
                {
                    continue;
                }
                if(*itr==*i)
                {
                    ok=true;
                }
            }
            if(!ok)
            {
                cout << -1 << "\n";
                return;
            }
        }

        bool is2[1<<17]={};
        is2[root]=1;
        // co[root]='W';

        vs.erase(vs.begin());

        for(auto itr=vs.begin(), jtr=vs.begin(); itr!=end(vs); itr=jtr)
        {
            vector<int> vvs;
            while(jtr!=end(vs) and d[*itr]==d[*jtr])
            {
                is2[*jtr]=1;
                co[*jtr]='W';
                vvs.emplace_back(*jtr);
                ++jtr;
            }

            for(int v : vvs)
            {
                bool f=false;
                for(pii e: g[v])
                {
                    int u,id; tie(u,id)=e;
                    if(is2[u])
                    {
                        w[id]=d[v];
                        f=1;
                        co[v]='B'+'W'-co[u];
                        break;
                    }
                }
                if(!f)
                {
                    cout << -1 << "\n";
                    return;
                }
            }
        }

        cout << co << "\n";
        for(int w_:w) cout << w_ << "\n";


        return;

        queue<int> que;
        bool is[1<<17]={};
        que.push(root);
        is[root]=1;
        co[root]='W';

        while(!que.empty())
        {
            int f=que.front();
            que.pop();
            for(pii e : g[f])
            {
                int ff=e.first;
                if(is[ff])
                {
                    if(!w[e.second]) w[e.second]=1e9;
                }
                else
                {
                    is[ff]=1;
                    w[e.second]=d[ff];
                    co[ff]='W'+'B'-co[f];
                    que.emplace(ff);
                }
            }
        }

        cout << co << "\n";
        for(int w_i : w)
        {
            cout << w_i << "\n";
        }
    }
}; // struct solver

int main(int argc, char *argv[])
{
    u32 t; // loop count
#ifdef LOCAL
    t = 1;
#else
    t = 1; // single test case
#endif
    // t = -1; // infinite loop
    // cin >> t; // case number given

    while(t--)
    {
        solver();
    }
}