P5191

Solution

首先图是一个 DAG,入度为 $0$ 的点就是不可能被别的点影响的点,所以可以跑拓扑排序。用 bitset 来存点集会快一些。

然后发现,对于每个 $s_i$ 都确定的事件就是它们能被到达的点集的或,而一定能发生就是它们的并,以此跑两遍拓扑排序即可维护。

至于判断是不是答案只需要确定它的点集并之后不变就行。

Code

#include <bits/stdc++.h>
using LL = long long;
const LL N = 1000;
vector<LL> g[N + 5];
LL deg[N + 5], x, v[N], a, b;
bitset<N + 5> f[N + 5];
vector<LL> res;

int main() {
    cin >> a >> b >> x;
    for (LL i = 1; i <= b; ++i) {
        LL u, w;
        cin >> u >> w;
        g[u].push_back(w);
        ++deg[w];
    }

    queue<LL> q;
    for (LL i = 1; i <= a; ++i)
        if (deg[i] == 0) q.push(i), f[i][i] = 1;

    while (!q.empty()) {
        LL u = q.front(); q.pop();
        for (auto w : g[u]) {
            --deg[w];
            f[w] |= f[u];
            if (deg[w] == 0) q.push(w);
        }
    }

    queue<LL> q2;
    for (LL i = 1; i <= x; ++i) {
        cin >> v[i];
        v[v[i]] = true;
        q2.push(v[i]);
    }

    while (!q2.empty()) {
        LL u = q2.front(); q2.pop();
        res.push_back(u);
        for (LL i = 1; i <= a; ++i) {
            if (v[i] != 0) continue;
            if ((f[i] & f[u]) == f[u]) {
                v[i] = true;
                q2.push(i);
            }
        }
        v[u] = -1;
    }

    sort(res.begin(), res.end());
    for (auto x : res) cout << x << " ";
    return 0;
}