Official

E - サーバーネットワークの一斉アップデート / Simultaneous Update of Server Network Editorial by MMNMM


強連結成分分解を行い、\(i\) 番目の強連結成分を \(C _ i=(C _ {i,1},C _ {i,2},\ldots)\) とします。

自己ループがないことから、サイズが \(1\) の強連結成分に含まれる頂点に対して操作を行ったとき、\(S(v)\) は空となり、どの頂点のセキュリティレベルも変化しません。 サイズが \(2\) 以上の強連結成分に含まれる頂点に対して操作を行ったとき、\(S(v)\) はその強連結成分となり、その強連結成分に含まれる頂点のセキュリティレベルが \(1\) だけ増加します。

よって、サイズ \(1\) の強連結成分に含まれる頂点 \(j\) であって \(W _ j\lt T _ j\) となるものが存在するとき、ネットワーク全体を基準達成の状態にすることはできません。 そうでないとき、それぞれの強連結成分に対して適切な回数操作を行うことで基準達成の状態にすることができます。

具体的には、\(i\) 番目の強連結成分に含まれている頂点に対して、合計 \(\max\Bigl\lbrace0,\max\lbrace T _ {C _ {i,j}}-W _ {C _ {i,j}}\rbrace \Bigr\rbrace\) 回操作を行うのが最適です。

実装例は以下のようになります。

#include <iostream>
#include <vector>
#include <atcoder/scc>
using namespace std;

int main() {
    int N, M;
    cin >> N >> M;

    // need[i] = T[i] - W[i]:頂点 i に対して何回操作を行う必要があるか
    vector<int> need(N);
    for (int i = 0; i < N; ++i) {
        int W;
        cin >> W;
        need[i] -= W;
    }
    for (int i = 0; i < N; ++i) {
        int T;
        cin >> T;
        need[i] += T;
    }

    // 強連結成分を求めて
    atcoder::scc_graph scc(N);
    for (int i = 0; i < M; ++i) {
        int u, v;
        cin >> u >> v;
        --u;
        --v;
        scc.add_edge(u, v);
    }

    // それぞれの強連結成分に対して必要な操作回数を求める
    long ans = 0;
    for (auto& g : scc.scc()) {
        int tmp = -1000000000;
        for (int x : g) {
            tmp = max(need[x], tmp);
        }
        // サイズ 1 の強連結成分には操作ができない
        if (g.size() == 1 && tmp > 0) {
            cout << -1 << endl;
            return 0;
        }
        ans += max(0, tmp);
    }
    cout << ans << endl;
    return 0;
}
from atcoder.scc import SCCGraph


N, M = map(int, input().split())

# need[i] = T[i] - W[i]:頂点 i に対して何回操作を行う必要があるか
need = [0 for i in range(N)]
for i, w in enumerate(map(int, input().split())):
    need[i] -= w
for i, t in enumerate(map(int, input().split())):
    need[i] += t

# 強連結成分を求めて
scc = SCCGraph(N)
for i in range(M):
    u, v = map(int, input().split())
    u -= 1
    v -= 1
    scc.add_edge(u, v)

# それぞれの強連結成分に対して必要な操作回数を求める
ans = 0
for g in scc.scc():
    tmp = -1000000000
    for x in g:
        tmp = max(tmp, need[x])

    # サイズ 1 の強連結成分には操作ができない
    if len(g) == 1 and tmp > 0:
        print(-1)
        break
 
    ans += max(0, tmp)
else:
    print(ans)

posted:
last update: