This documentation is automatically generated by online-judge-tools/verification-helper
#include "graph/others/offline-dag-reachability.hpp"
DAG(閉路のない有向グラフ) が与えられたとき, ある頂点からある頂点に到達できるかどうかを調べるクエリをビット並列により処理する. ちなみに, 閉路のあるグラフの場合は強連結成分分解して, 各強連結成分を縮約することで DAG に帰着される.
トポロジカルソートして頂点をトポロジカル順に見ると, ある頂点からどの頂点に到達できるかを判定できる. このとき, 各 bit を $1$ つのクエリに対応させて到達可能性を判定すると, ビット並列により処理できることとなり高速化が見込める.
offline_dag_reachability(g, qs)
: DAG g
について, qs
の各クエリについて頂点 qs[i].first
から qs[i].second
に到達できるか判定し, 到達できる場合は 1
, できない場合は 0
を格納して返す.$O(\frac {(E + V) Q} {B})$
$V$: 頂点数, $E$: 辺の本数, $Q$ クエリの個数, $B$: ワードサイズ
#pragma once
#include "../graph-template.hpp"
#include "topological-sort.hpp"
/**
* @brief Offline Dag Reachability(DAGの到達可能性クエリ)
*
*/
template <typename T>
vector<int> offline_dag_reachability(const Graph<T> &g,
vector<pair<int, int> > &qs) {
const int N = (int)g.size();
const int Q = (int)qs.size();
auto ord = topological_sort(g);
vector<int> ans(Q);
for (int l = 0; l < Q; l += 64) {
int r = min(Q, l + 64);
vector<int64_t> dp(N);
for (int k = l; k < r; k++) {
dp[qs[k].first] |= int64_t(1) << (k - l);
}
for (auto &idx : ord) {
for (auto &to : g[idx]) dp[to] |= dp[idx];
}
for (int k = l; k < r; k++) {
ans[k] = (dp[qs[k].second] >> (k - l)) & 1;
}
}
return ans;
}
#line 2 "graph/others/offline-dag-reachability.hpp"
#line 2 "graph/graph-template.hpp"
/**
* @brief Graph Template(グラフテンプレート)
*/
template <typename T = int>
struct Edge {
int from, to;
T cost;
int idx;
Edge() = default;
Edge(int from, int to, T cost = 1, int idx = -1)
: from(from), to(to), cost(cost), idx(idx) {}
operator int() const { return to; }
};
template <typename T = int>
struct Graph {
vector<vector<Edge<T> > > g;
int es;
Graph() = default;
explicit Graph(int n) : g(n), es(0) {}
size_t size() const { return g.size(); }
void add_directed_edge(int from, int to, T cost = 1) {
g[from].emplace_back(from, to, cost, es++);
}
void add_edge(int from, int to, T cost = 1) {
g[from].emplace_back(from, to, cost, es);
g[to].emplace_back(to, from, cost, es++);
}
void read(int M, int padding = -1, bool weighted = false,
bool directed = false) {
for (int i = 0; i < M; i++) {
int a, b;
cin >> a >> b;
a += padding;
b += padding;
T c = T(1);
if (weighted) cin >> c;
if (directed)
add_directed_edge(a, b, c);
else
add_edge(a, b, c);
}
}
inline vector<Edge<T> > &operator[](const int &k) { return g[k]; }
inline const vector<Edge<T> > &operator[](const int &k) const { return g[k]; }
};
template <typename T = int>
using Edges = vector<Edge<T> >;
#line 2 "graph/others/topological-sort.hpp"
#line 4 "graph/others/topological-sort.hpp"
/**
* @brief Topological Sort(トポロジカルソート)
*
*/
template <typename T>
vector<int> topological_sort(const Graph<T> &g) {
const int N = (int)g.size();
vector<int> deg(N);
for (int i = 0; i < N; i++) {
for (auto &to : g[i]) ++deg[to];
}
stack<int> st;
for (int i = 0; i < N; i++) {
if (deg[i] == 0) st.emplace(i);
}
vector<int> ord;
while (!st.empty()) {
auto p = st.top();
st.pop();
ord.emplace_back(p);
for (auto &to : g[p]) {
if (--deg[to] == 0) st.emplace(to);
}
}
return ord;
}
#line 5 "graph/others/offline-dag-reachability.hpp"
/**
* @brief Offline Dag Reachability(DAGの到達可能性クエリ)
*
*/
template <typename T>
vector<int> offline_dag_reachability(const Graph<T> &g,
vector<pair<int, int> > &qs) {
const int N = (int)g.size();
const int Q = (int)qs.size();
auto ord = topological_sort(g);
vector<int> ans(Q);
for (int l = 0; l < Q; l += 64) {
int r = min(Q, l + 64);
vector<int64_t> dp(N);
for (int k = l; k < r; k++) {
dp[qs[k].first] |= int64_t(1) << (k - l);
}
for (auto &idx : ord) {
for (auto &to : g[idx]) dp[to] |= dp[idx];
}
for (int k = l; k < r; k++) {
ans[k] = (dp[qs[k].second] >> (k - l)) & 1;
}
}
return ans;
}