#include using namespace std; #include "atcoder/fenwicktree.hpp" #include "atcoder/modint.hpp" using mint = atcoder::modint998244353; struct UnionFind { int n; vector par; vector mx; UnionFind(int n) : n(n), par(n, -1), mx(n) { iota(mx.begin(), mx.end(), 0); } int find(int x) { if (par[x] < 0) return x; return par[x] = find(par[x]); } void unite(int u, int v) { u = find(u); v = find(v); if (u == v) return; if (par[u] > par[v]) swap(u, v); par[u] += par[v]; par[v] = u; mx[u] = max(mx[u], mx[v]); } bool same(int u, int v) { return find(u) == find(v); } int get_max(int u) { return mx[find(u)]; } }; struct HLD { int n, path; std::vector> edges; std::vector siz; std::vector par; std::vector depth; std::vector path_ind; std::vector path_root; std::vector heavy_child; std::vector isheavy; std::vector L; std::vector R; HLD(int n) : n(n) { edges.resize(n); siz.assign(n, -1); par.assign(n, -1); depth.assign(n, -1); path_ind.assign(n, -1); heavy_child.assign(n, -1); isheavy.assign(n, false); L.assign(n, -1); R.assign(n, -1); } void read_edges(int indexed = 1) { int u, v; for (int i = 0; i < n - 1; i++) { std::cin >> u >> v; u -= indexed; v -= indexed; edges[u].push_back(v); edges[v].push_back(u); } } void add_edge(int u, int v) { edges[u].push_back(v); edges[v].push_back(u); } void build(int root = 0) { depth[root] = 0; std::stack st; std::vector route; st.push(root); route.push_back(root); while (!st.empty()) { int pos = st.top(); st.pop(); for (auto npos : edges[pos]) { if (depth[npos] == -1) { depth[npos] = depth[pos] + 1; par[npos] = pos; st.push(npos); route.push_back(npos); } } } reverse(route.begin(), route.end()); for (auto pos : route) { siz[pos] = 1; int ma = -1; for (auto npos : edges[pos]) { if (depth[npos] > depth[pos]) siz[pos] += siz[npos]; if (siz[npos] > ma) { ma = siz[npos]; heavy_child[pos] = npos; } } if (heavy_child[pos] != -1) isheavy[heavy_child[pos]] = true; } isheavy[root] = true; path = 0; st.push(~root); st.push(root); path_root.push_back(root); int cc = 0; while (!st.empty()) { int pos = st.top(); st.pop(); if (pos >= 0) { L[pos] = cc++; if (!isheavy[pos]) { path++; path_root.push_back(pos); } path_ind[pos] = path; for (auto npos : edges[pos]) { if (npos == par[pos] || npos == heavy_child[pos]) continue; st.push(~npos); st.push(npos); } if (heavy_child[pos] != -1) { int npos = heavy_child[pos]; st.push(~npos); st.push(npos); } } else { pos = ~pos; R[pos] = cc; } } } std::vector> get_path(int u, int v) { std::vector ll; std::vector rr; ll.push_back(u); rr.push_back(v); while (path_ind[u] != path_ind[v]) { if (depth[path_root[path_ind[u]]] >= depth[path_root[path_ind[v]]]) { u = path_root[path_ind[u]]; ll.push_back(u); u = par[u]; ll.push_back(u); } else { v = path_root[path_ind[v]]; rr.push_back(v); v = par[v]; rr.push_back(v); } } reverse(rr.begin(), rr.end()); ll.insert(ll.end(), rr.begin(), rr.end()); int n = ll.size(); std::vector> res(n / 2); for (int i = 0; i < n; i += 2) { res[i / 2] = {ll[i], ll[i + 1]}; } return res; } int lca(int u, int v) { while (path_ind[u] != path_ind[v]) { if (depth[path_root[path_ind[u]]] >= depth[path_root[path_ind[v]]]) u = par[path_root[path_ind[u]]]; else v = par[path_root[path_ind[v]]]; } return (depth[u] <= depth[v]) ? u : v; } int dist(int u, int v) { int p = lca(u, v); return depth[u] + depth[v] - 2 * depth[p]; } template std::vector reorder(std::vector &A, bool rev = false) { assert(int(A.size()) == n); std::vector ret(n); for (int i = 0; i < n; i++) { ret[L[i]] = A[i]; } if (rev) reverse(ret.begin(), ret.end()); return ret; } }; void solve() { int n, m; cin >> n >> m; vector E(n, vector()); for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; E[v - 1].emplace_back(u - 1); } UnionFind UF(n); HLD hld(n); for (int v = 0; v < n; v++) { for (auto u : E[v]) { if (!UF.same(u, v)) { hld.add_edge(UF.get_max(u), v); UF.unite(u, v); } } } hld.build(); atcoder::fenwick_tree bit(n); for (int v = 0; v < n; v++) { vector> lr; for (auto u : E[v]) { auto path = hld.get_path(u, v); for (auto [uu, vv] : path) { uu = hld.L[uu]; vv = hld.L[vv]; if (uu > vv) swap(uu, vv); lr.emplace_back(uu, vv + 1); } } sort(lr.begin(), lr.end()); mint tot = 0; int mar = 0; for (auto [l, r] : lr) { l = max(l, mar); if (l < r) { tot += bit.sum(l, r); } mar = max(mar, r); } bit.add(hld.L[v], tot + 1); } mint ans = bit.sum(0, n); cout << ans.val() << endl; } int main() { solve(); }