結果
| 問題 |
No.1326 ふたりのDominator
|
| コンテスト | |
| ユーザー |
Felerius
|
| 提出日時 | 2021-05-25 18:41:02 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 119 ms / 2,000 ms |
| コード長 | 7,973 bytes |
| コンパイル時間 | 3,070 ms |
| コンパイル使用メモリ | 237,580 KB |
| 最終ジャッジ日時 | 2025-01-21 18:25:25 |
|
ジャッジサーバーID (参考情報) |
judge4 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 24 |
ソースコード
#pragma GCC optimize("fast-math")
// begin "cp-lib/boilerplate.hpp"
#include <bits/stdc++.h>
#define _choose(_1, _2, _3, chosen, ...) chosen
#define _rep(i, l, r) for (int i = l; i < r; ++i)
#define _rep0(i, r) _rep(i, 0, r)
#define _repr(i, r, l) for (int i = r; i >= l; --i)
#define _repr0(i, r) _repr(i, r, 0)
#define rep(...) _choose(__VA_ARGS__, _rep, _rep0, suppress_warning)(__VA_ARGS__)
#define repr(...) _choose(__VA_ARGS__, _repr, _repr0, suppress_warning)(__VA_ARGS__)
#define all(a) ::begin(a),::end(a)
#define trav(a, b) for (auto&& a : b)
using namespace std;
namespace cp_lib {}
using ll = long long;
using ld = long double;
using u64 = uint64_t;
using u32 = uint32_t;
[[maybe_unused]] static constexpr int INF = int(1e9 + 5);
[[maybe_unused]] static constexpr ll INFL = ll(INF) * INF;
[[maybe_unused]] static mt19937 rng(u32(chrono::duration_cast<chrono::nanoseconds>(chrono::high_resolution_clock::now().time_since_epoch()).count()));
template <class C> int sz(const C& c) { return int(::size(c)); }
// end "cp-lib/boilerplate.hpp"
// begin "cp-lib/graph/_detail.hpp"
namespace cp_lib {
struct Identity {
template <class T> constexpr T&& operator()(T&& t) const noexcept { return forward<T>(t); }
};
template <class A, class M>
struct Graph {
const A& adj;
int n;
M map;
Graph(const A& adj_, int n_, M&& map_) : adj{adj_}, n{n_}, map{forward<M>(map_)} {}
Graph(const A& adj_, M&& map_) : adj{adj_}, n{sz(adj)}, map{forward<M>(map_)} {}
Graph(const A& adj_, int n_) : adj{adj_}, n{n_}, map{Identity{}} {}
explicit Graph(const A& adj_) : adj{adj_}, n{sz(adj)}, map{Identity{}} {}
};
template <class A> Graph(const A&, int) -> Graph<A, Identity>;
template <class A> Graph(const A&) -> Graph<A, Identity>;
}
// end "cp-lib/graph/_detail.hpp"
// begin "cp-lib/graph/lca.hpp"
// begin "../ds/rmq.hpp"
// begin "../bit.hpp"
namespace cp_lib {
template <class T> constexpr inline bool is_pow2(T n) { return n && !(n & (n - 1)); }
template <class T> constexpr inline int floor_log2(T n) { return n ? 63 - __builtin_clzll(n) : 0; }
template <class T> constexpr inline int ceil_log2(T n) { return floor_log2(n) + !is_pow2(n); }
}
// end "../bit.hpp"
namespace cp_lib {
namespace _rmq_detail {
template <class T, bool Max> T minmax(T a, T b) { return (a < b) ^ Max ? a : b; }
}
template <class T, T (*Combine)(T, T)>
struct SparseTable {
vector<vector<T>> d = {};
SparseTable() = default;
explicit SparseTable(const vector<T>& v) {
int n = sz(v), k = floor_log2(n);
d.assign(k + 1, v);
rep(i, k) rep(j, n)
d[i + 1][j] = Combine(d[i][j], d[i][min(j + (1 << i), n - 1)]);
}
// Aggregate for [l, r)
T query(int l, int r) const {
int k = floor_log2(r - l);
return Combine(d[k][l], d[k][r - (1 << k)]);
}
};
template <class T>
using Rmq = SparseTable<T, _rmq_detail::minmax<T, false>>;
template <class T>
using Rmaxq = SparseTable<T, _rmq_detail::minmax<T, true>>;
}
// end "../ds/rmq.hpp"
namespace cp_lib {
struct LowestCommonAncestor {
vector<int> time, euler;
Rmq<int> rmq;
template <class G>
LowestCommonAncestor(G&& graph, int root) {
auto [adj, n, to] = Graph(forward<G>(graph));
if (!n) return;
time.resize(n);
vector<int> d;
int t = 0;
auto dfs = [&, &adj=adj, &to=to](int v, int p, auto&& self) -> void {
time[v] = t++;
trav(e, adj[v])
if (to(e) != p)
euler.push_back(v), d.push_back(time[v]), self(to(e), v, self);
};
dfs(root, -1, dfs);
rmq = Rmq<int>(d);
}
int lca(int u, int v) const {
if (u == v) return u;
auto [l, r] = minmax(time[u], time[v]);
return euler[rmq.query(l, r)];
}
bool on_path(int v, pair<int, int> path) const {
auto [a, b] = path;
return minmax(lca(a, v), lca(b, v)) == minmax(v, lca(a, b));
}
};
}
// end "cp-lib/graph/lca.hpp"
using namespace cp_lib;
template <class G, class F>
void find_bridges(G&& graph, F&& f) {
auto [adj, n, to] = Graph(forward<G>(graph));
vector<int> idx(n, -1), stack;
auto dfs = [&, &adj=adj, &to=to](int v, int p, auto&& self) -> int {
int up = idx[v] = sz(stack);
stack.push_back(v);
for (auto it = begin(adj[v]), it_end = end(adj[v]); it != it_end; ++it) {
int v2 = to(*it);
if (v2 == p) { p = -1; continue; }
int up2 = (idx[v2] == -1 ? self(v2, v, self) : idx[v2]);
if (up2 > idx[v])
f(v, it, begin(stack) + idx[v2], end(stack)), stack.resize(idx[v2]);
up = min(up, up2);
}
return up;
};
rep(i, n) {
if (idx[i] != -1) continue;
dfs(i, -1, dfs);
f(-1, end(adj[0]), all(stack));
stack.clear();
}
}
struct BlockCutTree {
vector<int> node;
vector<bool> is_cut;
vector<vector<int>> tree;
template <class G>
explicit BlockCutTree(G&& graph) {
auto [adj, n, to] = Graph(forward<G>(graph));
vector<int> idx = node = vector(n, -1), stack;
is_cut = vector(n, false);
auto make_component = [&](int rem) {
int vt = sz(tree);
tree.emplace_back();
while (sz(stack) > rem) {
int v = stack.back(); stack.pop_back();
if (!is_cut[v])
node[v] = vt;
else if (!sz(tree[node[v]]) || tree[node[v]].back() != vt)
tree[vt].push_back(node[v]), tree[node[v]].push_back(vt);
}
};
auto dfs = [&, &adj=adj, &to=to](int v, int p, int8_t root, auto&& self) -> int {
int up = idx[v] = sz(stack);
trav(e, adj[v]) {
int v2 = to(e);
if (v2 == p) continue;
if (idx[v2] == -1 || idx[v2] < idx[v])
stack.push_back(v), stack.push_back(v2);
if (idx[v2] != -1) { up = min(up, idx[v2]); continue; }
int up2 = self(v2, v, 0, self);
up = min(up, up2);
if (up2 >= idx[v]) {
if (root == 2) { --root; continue; }
if (!is_cut[v])
is_cut[v] = true, node[v] = sz(tree), tree.emplace_back();
make_component(idx[v2] - 2);
if (root == 1)
--root, make_component(0);
}
}
return up;
};
rep(i, n) {
if (idx[i] != -1) continue;
dfs(i, -1, 2, dfs);
if (sz(stack)) make_component(0);
}
}
};
int main() {
cin.tie(0)->sync_with_stdio(false);
int n, m; cin >> n >> m;
vector adj(n, vector<int>());
rep(_, m) {
int u, v; cin >> u >> v; --u, --v;
adj[u].push_back(v);
adj[v].push_back(u);
}
BlockCutTree bct(adj);
LowestCommonAncestor lca(bct.tree, 0);
vector depth(sz(bct.tree), -1);
auto dfs = [&](int v, int p, auto&& self) -> void {
trav(v2, bct.tree[v])
if (v2 != p)
depth[v2] = depth[v] + 1, self(v2, v, self);
};
rep(i, sz(bct.tree))
if (depth[i] == -1)
depth[i] = 0, dfs(i, -1, dfs);
int q; cin >> q;
while (q--) {
int u, v; cin >> u >> v; --u, --v;
int ut = bct.node[u], vt = bct.node[v];
int l = lca.lca(ut, vt);
int d = depth[ut] + depth[vt] - 2 * depth[l];
d -= bct.is_cut[u] + bct.is_cut[v];
cout << max(0, d / 2) << '\n';
}
}
Felerius