結果
| 問題 | No.2588 Increasing Record | 
| コンテスト | |
| ユーザー |  | 
| 提出日時 | 2023-11-24 15:46:48 | 
| 言語 | PyPy3 (7.3.15) | 
| 結果 | 
                                AC
                                 
                             | 
| 実行時間 | 1,472 ms / 3,000 ms | 
| コード長 | 6,932 bytes | 
| コンパイル時間 | 511 ms | 
| コンパイル使用メモリ | 82,612 KB | 
| 実行使用メモリ | 200,792 KB | 
| 最終ジャッジ日時 | 2024-09-27 06:39:27 | 
| 合計ジャッジ時間 | 39,669 ms | 
| ジャッジサーバーID (参考情報) | judge5 / judge2 | 
(要ログイン)
| ファイルパターン | 結果 | 
|---|---|
| sample | AC * 3 | 
| other | AC * 44 | 
ソースコード
MOD = 998244353
class UnionFind:
    def __init__(self, n):
        self.n = n
        self.par = [-1] * n
        self.group_ = n
    def find(self, x):
        if self.par[x] < 0:
            return x
        lst = []
        while self.par[x] >= 0:
            lst.append(x)
            x = self.par[x]
        for y in lst:
            self.par[y] = x
        return x
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return False
        if self.par[x] > self.par[y]:
            x, y = y, x
        self.par[x] += self.par[y]
        self.par[y] = x
        self.group_ -= 1
        return True
    def size(self, x):
        return -self.par[self.find(x)]
    def same(self, x, y):
        return self.find(x) == self.find(y)
    @property
    def group(self):
        return self.group_
class BIT:
    def __init__(self, n):
        self.n = n
        self.data = [0] * (n + 1)
        if n == 0:
            self.n0 = 0
        else:
            self.n0 = 1 << (n.bit_length() - 1)
    def sum_(self, i):
        s = 0
        while i > 0:
            s += self.data[i]
            i -= i & -i
        return s
    def sum(self, l, r=-1):
        if r == -1:
            return self.sum_(l)
        else:
            return self.sum_(r) - self.sum_(l)
    def get(self, i):
        return self.sum(i, i + 1)
    def add(self, i, x):
        i += 1
        while i <= self.n:
            self.data[i] += x
            i += i & -i
    def lower_bound(self, x):
        if x <= 0:
            return 0
        i = 0
        k = self.n0
        while k > 0:
            if i + k <= self.n and self.data[i + k] < x:
                x -= self.data[i + k]
                i += k
            k //= 2
        return i + 1
class HLD:
    def __init__(self, n, edges=None):
        self.n = n
        if edges is None:
            self.edges = [[] for _ in range(n)]
        else:
            self.edges = edges
            # コピーしてないので注意
        self.size = [-1] * n
        self.par = [-1] * n
        self.depth = [-1] * n
        self.path_ind = [-1] * n
        self.path_root = []
        self.heavy_child = [-1] * n
        self.isheavy = [False] * n
        self.L = [-1] * n
        self.R = [-1] * n
    def add_edge(self, u, v):
        self.edges[u].append(v)
        self.edges[v].append(u)
    def read_edges(self, indexed=1):
        for _ in range(self.n - 1):
            u, v = map(int, input().split())
            u -= indexed
            v -= indexed
            self.add_edge(u, v)
    def build(self, root=0):
        self.depth[root] = 0
        st = [root]
        route = [root]
        while st:
            pos = st.pop()
            for npos in self.edges[pos]:
                if self.depth[npos] == -1:
                    self.depth[npos] = self.depth[pos] + 1
                    self.par[npos] = pos
                    st.append(npos)
                    route.append(npos)
        for pos in route[::-1]:
            self.size[pos] = 1
            ma = -1
            for npos in self.edges[pos]:
                if self.size[npos] != -1:
                    self.size[pos] += self.size[npos]
                    if self.size[npos] > ma:
                        ma = self.size[npos]
                        self.heavy_child[pos] = npos
            if ma != -1:
                self.isheavy[self.heavy_child[pos]] = True
        self.isheavy[root] = True
        path = 0
        st = [~root, root]
        self.path_root = [root]
        cc = 0
        while st:
            pos = st.pop()
            if pos >= 0:
                self.L[pos] = cc
                cc += 1
                if not self.isheavy[pos]:
                    path += 1
                    self.path_root.append(pos)
                self.path_ind[pos] = path
                for npos in self.edges[pos]:
                    if npos == self.par[pos] or npos == self.heavy_child[pos]:
                        continue
                    st.append(~npos)
                    st.append(npos)
                if self.heavy_child[pos] != -1:
                    npos = self.heavy_child[pos]
                    st.append(~npos)
                    st.append(npos)
            else:
                self.R[~pos] = cc
    def get_path(self, u, v):
        ll = [u]
        rr = [v]
        while self.path_ind[u] != self.path_ind[v]:
            if (
                self.depth[self.path_root[self.path_ind[u]]]
                >= self.depth[self.path_root[self.path_ind[v]]]
            ):
                u = self.path_root[self.path_ind[u]]
                ll.append(u)
                u = self.par[u]
                ll.append(u)
            else:
                v = self.path_root[self.path_ind[v]]
                rr.append(v)
                v = self.par[v]
                rr.append(v)
        ll += rr[::-1]
        res = []
        for i in range(0, len(ll), 2):
            res.append((ll[i], ll[i + 1]))
        return res
    def lca(self, u, v):
        while self.path_ind[u] != self.path_ind[v]:
            if (
                self.depth[self.path_root[self.path_ind[u]]]
                >= self.depth[self.path_root[self.path_ind[v]]]
            ):
                u = self.par[self.path_root[self.path_ind[u]]]
            else:
                v = self.par[self.path_root[self.path_ind[v]]]
        if self.depth[u] >= self.depth[v]:
            return v
        else:
            return u
    def dist(self, u, v):
        return self.depth[u] + self.depth[v] - 2 * self.depth[self.lca(u, v)]
    def reorder(self, A, rev=False):
        ret = [0] * self.n
        for i in range(self.n):
            ret[self.L[i]] = A[i]
        if rev:
            ret = ret[::-1]
        return ret
n, m = map(int, input().split())
assert 2 <= n <= 200000
assert 1 <= m <= 200000
E = [[] for _ in range(n)]
se = set()
for _ in range(m):
    u, v = map(int, input().split())
    assert 1 <= u < v <= n
    assert u * n + v not in se
    se.add(u * n + v)
    E[v - 1].append(u - 1)
UF = UnionFind(n)
hld = HLD(n)
ma = [i for i in range(n)]
for v in range(n):
    for u in E[v]:
        if not UF.same(u, v):
            hld.add_edge(ma[UF.find(u)], v)
            UF.unite(u, v)
            ma[UF.find(u)] = v
assert UF.group == 1
hld.build()
bit = BIT(n)
for v in range(n):
    lr = []
    for u in E[v]:
        for uu, vv in hld.get_path(u, v):
            uu = hld.L[uu]
            vv = hld.L[vv]
            if uu > vv:
                uu, vv = vv, uu
            lr.append(uu * (n + 1) + (vv + 1))
    lr.sort()
    tot = 0
    mar = 0
    for tmp in lr:
        l = tmp // (n + 1)
        r = tmp - l * (n + 1)
        l = max(l, mar)
        if l < r:
            tot += bit.sum(l, r)
        mar = max(mar, r)
    bit.add(hld.L[v], tot % MOD + 1)
ans = bit.sum(0, n)
print(ans % MOD)
            
            
            
        