#include #if __has_include() #include std::istream &operator>>(std::istream &is, atcoder::modint &v) { long long value; is >> value; v = value; return is; } std::ostream &operator<<(std::ostream &os, const atcoder::modint &v) { os << v.val(); return os; } std::ostream &operator<<(std::ostream &os, const atcoder::modint998244353 &v) { os << v.val(); return os; } std::istream &operator>>(std::istream &is, atcoder::modint998244353 &v) { long long x; is >> x; v = x; return is; } std::ostream &operator<<(std::ostream &os, const atcoder::modint1000000007 &v) { os << v.val(); return os; } std::istream &operator>>(std::istream &is, atcoder::modint1000000007 &v) { long long x; is >> x; v = x; return is; } #endif using namespace std; using ll = long long; using lint = __int128_t; using pll = pair; #define newl '\n'; #define rep(i, s, t) for (ll i = s; i < (ll)(t); i++) #define rrep(i, s, t) for (ll i = (ll)(t) - 1; i >= (ll)(s); i--) #define all(x) begin(x), end(x) #define SZ(x) ll(x.size()) #define eb emplace_back #define pb push_back #define TT template TT using vec = vector; TT using vvec = vec>; TT using vvvec = vec>; TT using minheap = priority_queue, greater>; TT using maxheap = priority_queue; TT bool chmin(T &x, T y) { return x > y ? (x = y, true) : false; } TT bool chmax(T &x, T y) { return x < y ? (x = y, true) : false; } TT T smod(T x, T mod) { x %= mod; if (x < 0) x += mod; return x; } TT bool rng(T l, T x, T r) { return l <= x && x < r; } TT T flr(T a, T b) { if (b < 0) a = -a, b = -b; return a >= 0 ? a / b : (a + 1) / b - 1; } TT T cil(T a, T b) { if (b < 0) a = -a, b = -b; return a > 0 ? (a - 1) / b + 1 : a / b; } TT T sqr(T x) { return x * x; } //{0, 1, ... } -> {p[0], p[1], ...} template void rearrange(vector &A, vector const &p) { assert(p.size() == A.size()); vector a = A; for (int i = 0; i < ssize(A); ++i) { a[i] = A[p[i]]; } swap(a, A); } template void rearrange(vector &A, vector p, vector &...rest) { rearrange(A, p); (rearrange(rest, p), ...); } template void rearrange(vector &A, Compare cmp, vector &...rest) { vector p(ssize(A)); iota(p.begin(), p.end(), 0); sort(p.begin(), p.end(), cmp); rearrange(A, p); (rearrange(rest, p), ...); } struct io_setup { io_setup() { ios::sync_with_stdio(false); std::cin.tie(nullptr); cout << fixed << setprecision(15); } } io_setup; template ostream &operator<<(ostream &os, const pair &p) { os << p.first << " " << p.second; return os; } TT ostream &operator<<(ostream &os, const vector &v) { for (size_t i = 0; i < v.size(); i++) { os << v[i] << (i + 1 != v.size() ? " " : ""); } return os; } template ostream &operator<<(ostream &os, const array &v) { for (size_t i = 0; i < n; i++) { os << v[i] << (i + 1 != n ? " " : ""); } return os; } template ostream &operator<<(ostream &os, const vvec &v) { for (size_t i = 0; i < v.size(); i++) { os << v[i] << (i + 1 != v.size() ? "\n" : ""); } return os; } TT istream &operator>>(istream &is, vector &v) { for (size_t i = 0; i < v.size(); i++) { is >> v[i]; } return is; } #if __has_include() #include #else #define dbg(...) true #define DBG(...) true #define OUT(...) true #endif template struct Edge { int to; T cost; int id; static constexpr T INF = numeric_limits::max() / 2; Edge(int to = 0, T cost = 1, int id = -1) : to(to), cost(cost), id(id) { } }; template struct Graph : vector>> { #define n int(this->size()) using vector>>::vector; void add(int s, int t, T w = 1, int id = -1) { (*this)[s].emplace_back(t, w, id); if constexpr (directed == false) { (*this)[t].emplace_back(s, w, id); } } #undef n }; template struct Tree : Graph { #define n int(this->size()) using Graph::Graph; #undef n }; namespace Graph_lib { #define inf Edge::INF template vector DFS(Graph const &g, int s) { int n = g.size(); assert(0 <= s && s < n); vector d(n, inf); d[s] = 0; queue que; que.push(s); while (que.empty() == false) { int v = que.front(); que.pop(); for (auto &e : g[v]) { assert(e.cost == 1); if (chmin(d[e.to], d[v] + e.cost)) { que.push(e.to); } } } return d; } template vector dijkstra(Graph const &g, int s) { int n = g.size(); vector d(n, inf); d[s] = 0; priority_queue, vector>, greater>> que; que.push({d[s], s}); while (que.empty() == false) { auto [c, v] = que.top(); que.pop(); if (d[v] < c) continue; for (auto &e : g[v]) { assert(e.cost >= 0); if (chmin(d[e.to], d[v] + e.cost)) { que.push({d[e.to], e.to}); } } } return d; } template pair> bellman_ford(Graph const &g, int s) { int n = g.size(); vector d(n, inf); d[s] = 0; int last = -1; for (int i = 0; i <= n; i++) { bool f = false; for (int v = 0; v < n; v++) if (d[v] != inf) { for (auto &e : g[v]) { if (chmin(d[e.to], d[v] + e.cost)) { f = true; } } } if (f) last = i; } if (last == n) return {true, d}; else return {false, d}; } template bool has_negative_cycle(Graph const &g) { if (g.size() == 0) return false; auto [f, d] = bellman_ford(g, 0); return f; } template vector> warshall(Graph const &g) { int n = g.size(); vector> d(n, vector(n, inf)); for (int i = 0; i < n; i++) { d[i][i] = 0; for (auto &e : g[i]) { chmin(d[i][e.to], e.cost); } } for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { if (d[i][k] == inf) continue; for (int j = 0; j < n; j++) { if (d[k][j] == inf) continue; d[i][j] = min(d[i][j], d[i][k] + d[k][j]); } } } return d; } template pair, vector> cycle_detection(Graph const &g, int v = -1) { int n = g.size(); vector in(n, false), out(n, false); vector vs, es; const int fin = INT_MAX; auto dfs = [&](auto f, int v, int p) -> int { bool prev_edge = false; in[v] = true; for (auto e : g[v]) { if constexpr (directed == false) { if (e.to == p) { if (prev_edge == false) { prev_edge = true; continue; } else { vs.push_back(v); es.push_back(e.id); out[v] = true; return e.to; } } } if (in[e.to] && out[e.to] == false) { vs.push_back(v); es.push_back(e.id); out[v] = true; return v == e.to ? fin : e.to; } if (in[e.to] == false) { int root = f(f, e.to, v); if (root != -1 && root != fin) { vs.push_back(v); es.push_back(e.id); out[v] = true; return (v == root ? fin : root); } else if (root == fin) { out[v] = true; return fin; } } } out[v] = true; return -1; }; int s = 0, t = n; if (v != -1) s = v, t = v + 1; for (int i = s; i < t; i++) { if (in[i] == false) { dfs(dfs, i, -1); if (vs.empty() == false) { reverse(vs.begin(), vs.end()); reverse(es.begin(), es.end()); return make_pair(vs, es); } } } return make_pair(vs, es); } // ret[v] := vを含む連結成分が // -1 : 二部グラフでない 0 : 色塗ったら0 1 : 色塗ったら1 //  色塗りは0から始める template vector bipartite_check(Graph const &g) { int n = g.size(); vector col(n, -1); vector> gs; auto dfs = [&](auto f, int v, int c, vector &vs) -> void { col[v] = c; vs.push_back(v); for (auto &e : g[v]) if (col[e.to] == -1) { f(f, e.to, c ^ 1, vs); } }; for (int i = 0; i < n; i++) { if (col[i] == -1) { vector vs; dfs(dfs, i, 0, vs); gs.push_back(vs); } } for (auto &vs : gs) { bool ng = false; for (auto v : vs) { for (auto &e : g[v]) { if (col[v] == col[e.to]) { ng = true; } } } if (ng) { for (auto v : vs) col[v] = -1; } } return col; } #undef inf }; // namespace Graph_lib namespace Tree_lib { #define inf Edge::INF template vector dist(Tree const &tr, int s) { int n = tr.size(); vector res(n, inf); res[s] = 0; queue que; que.push(s); while (!que.empty()) { int v = que.front(); que.pop(); for (auto &e : tr[v]) if (chmin(res[e.to], res[v] + e.cost)) { que.push(e.to); } } return res; } template vector path(Tree const &tr, int s, int t) { vector res; auto dfs = [&](auto f, int v, int p = -1) -> bool { if (v == t) { return true; } for (auto &e : tr[v]) if (e.to != p) { if (f(f, e.to, v)) { res.push_back(e.to); return true; } } return false; }; dfs(dfs, s); res.push_back(s); reverse(res.begin(), res.end()); return res; } // diam() ... (直径, (直径の端u, 直径の端v)) template pair> diam(Tree const &tr) { int n = tr.size(); int u, v; T d, tmp; vector ds = dist(tr, 0); tmp = ds[0], u = 0; for (int i = 1; i < n; i++) { if (chmax(tmp, ds[i])) u = i; } vector ds2 = dist(tr, u); d = ds2[0], v = 0; for (int i = 1; i < n; i++) { if (chmax(d, ds2[i])) v = i; } pair> res; res.first = d; res.second.first = u; res.second.second = v; return res; } // {直径0, 直径1 or -1} template pair center(Tree const &tr) { auto [d, p] = diam(tr); auto ph = path(tr, p.first, p.second); int m = (ph.size() + 1) / 2 - 1; if (ph.size() % 2 == 1) return {ph[m], -1}; else return {ph[m], ph[m + 1]}; } template vector> maximum_matching(Tree const &tr) { vector> ret; auto dfs = [&](auto f, int v, int p) -> bool { bool used = false; for (auto &e : tr[v]) if (e.to != p) { bool used_to = f(f, e.to, v); if (used_to == false && used == false) { used = true; ret.emplace_back(v, e.to); } } return used; }; dfs(dfs, 0, -1); return ret; } //{存在するか、頂点のペアの集合} template pair>> perfect_matching(Tree const &tr) { if (tr.size() % 2 == 1) return {false, {}}; auto match = maximum_matching(tr); if (match.size() * 2 == tr.size()) { return {true, match}; } else { return {false, match}; } } #undef inf }; // namespace Tree_lib using mint = atcoder::modint998244353; using P = array; /* x=0にすると、操作を無視できる いつもの全域木 */ pair> solve(ll n, ll m, vector B, Graph g, map id) { { auto col = Graph_lib::bipartite_check(g); if (col[0] != -1) { vector sm(2, 0); rep(i, 0, n) sm[col[i]] += B[i]; if (sm[0] != sm[1]) { return {false, {}}; } } } atcoder::dsu uf(n); Tree tr(n); rep(i, 0, n) for (auto e : g[i]) { if (uf.same(i, e.to) == false) { uf.merge(i, e.to); tr.add(i, e.to); } } auto col = Graph_lib::bipartite_check(tr); vector sm(2, 0); rep(i, 0, n) sm[col[i]] += B[i]; vector same(2, pll(-1, -1)); rep(i, 0, n) for (auto e : g[i]) if (col[i] == col[e.to]) { same[col[i]] = pll(i, e.to); } vector A(n, 0); map ret; auto add = [&](ll u, ll v, mint val) { ret[minmax(u, v)] += val; A[u] += val; A[v] += val; }; if (same[0] != pll(-1, -1)) { mint v = (sm[1] - sm[0]) / 2; add(same[0].first, same[0].second, -v); // sm[0] += 2*v; } else if(same[1] != pll(-1, -1)) { mint v = (sm[0] - sm[1]) / 2; add(same[1].first, same[1].second, -v); // sm[1] += 2*v; } auto dfs = [&](auto f, int v, int p) -> void { for (auto e : tr[v]) if (e.to != p) { f(f, e.to, v); mint d = B[e.to] - A[e.to]; add(v, e.to, d); }; return; }; dfs(dfs, 0, -1); vector ans(m, 0); for (auto p : ret) { auto [uv, val] = p; ans[id[uv]] += val; } return {true, ans}; } int main() { ll n, m; cin >> n >> m; vector B(n); cin >> B; Graph g(n); map id; rep(i, 0, m) { ll u, v; cin >> u >> v; u--, v--; g.add(u, v); id[minmax(u, v)] = i; } auto [flg, ret] = solve(n, m, B, g, id); if(flg == false) { cout << -1 << endl; } else { cout << ret << endl; } } /* 同じ議論を繰り返さない do smth instead of nothing and stay organized WRITE STUFF DOWN DON'T GET STUCK ON ONE APPROACH */