結果
| 問題 | No.1326 ふたりのDominator |
| コンテスト | |
| ユーザー |
Felerius
|
| 提出日時 | 2022-02-13 01:34:34 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 104 ms / 2,000 ms |
| コード長 | 14,622 bytes |
| コンパイル時間 | 4,257 ms |
| コンパイル使用メモリ | 293,688 KB |
| 最終ジャッジ日時 | 2025-01-27 22:54:57 |
|
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 24 |
ソースコード
#pragma GCC optimize("fast-math")
#include <bits/stdc++.h>
#ifdef LOCAL
# include <dbg.h>
#else
# define dbg(...) do {} while (0)
#endif
#define cp_lib_4th(_1, _2, _3, x, ...) x
#define cp_lib_rep(i, l, r) for (int i = (l); (i) < (r); ++(i))
#define cp_lib_rep0(i, r) cp_lib_rep(i, 0, r)
#define rep(...) cp_lib_4th(__VA_ARGS__, cp_lib_rep, cp_lib_rep0, _)(__VA_ARGS__)
#define cp_lib_repr(i, r, l, ...) for (int i = (r); (i) >= (l); --(i))
#define repr(...) cp_lib_repr(__VA_ARGS__, 0)
#define all(a) ::begin(a),::end(a)
#define trav(a, b) for (auto&& a : (b))
using namespace std;
using ll = long long;
using ld = long double;
[[maybe_unused]] static constexpr int INF = int(1e9 + 5);
[[maybe_unused]] static constexpr ll INFL = ll(INF) * INF;
template <class C> int sz(const C& c) { return int(::size(c)); }
#ifdef CP_LIB_DEBUG
#define cp_lib_assert(expr) \
do { if (!(expr)) { \
::cerr << "assertion failed: " << #expr << " (" << __FILE__ << ':' << __LINE__ << ")\n"; \
::abort(); \
} } while (0)
#else
#define cp_lib_assert(expr)
#endif
#if __cplusplus < 202002L
struct identity { template <class T> constexpr T&& operator()(T&& t) const noexcept { return forward<T>(t); }; };
#endif
#if __cpp_lib_remove_cvref < 201711L
template <class T> using remove_cvref_t = remove_cv_t<remove_reference_t<T>>;
#endif
namespace cp_lib_type_meta {
struct NoOp { template <class... Args> constexpr void operator()(Args&&...) const noexcept {} };
template <class T, class = void> constexpr bool is_tuple_like = false;
template <class T> constexpr bool is_tuple_like<T, void_t<tuple_element_t<0, T>>> = true;
}
namespace cp_lib_modint { struct ModIntTag {}; }
#include <unistd.h>
namespace cp_lib_io {
constexpr int BUF_SIZE = 1 << 20;
constexpr array<array<char, 4>, 10'000> DIGITS = []{
array<array<char, 4>, 10'000> digits{};
for (int i = 3, d = 1; i >= 0; --i, d *= 10)
rep(j, 10'000)
digits[j][i] = char('0' + j / d % 10);
return digits;
}();
array<char, BUF_SIZE> ibuf, obuf;
char *iptr = data(ibuf), *iend = iptr, *optr = data(obuf);
template <class T> constexpr bool is_std_array = false;
template <class T, size_t I> constexpr bool is_std_array<array<T, I>> = true;
void flush() {
for (auto* p = begin(obuf); p != optr; p += write(STDOUT_FILENO, p, optr - p));
optr = begin(obuf);
}
int _flush_atexit = []{ atexit(flush); return 0; }();
void refill() {
memmove(begin(ibuf), iptr, iend - iptr);
iend -= iptr - begin(ibuf);
iptr = begin(ibuf);
iend += read(STDIN_FILENO, iend, end(ibuf) - 1 - iend);
*iend = '\0';
}
template <class T, class T2 = remove_cvref_t<T>>
void print(T&& val) {
if (end(obuf) - optr < 64)
flush();
if constexpr (is_same_v<T2, char>)
*optr++ = val;
else if constexpr (is_same_v<T2, bool> || is_same_v<T2, vector<bool>::reference>)
return print(int(val));
else if constexpr (is_integral_v<T2> && is_signed_v<T2>) {
if (val < 0)
*optr++ = '-';
using U = make_unsigned_t<T2>;
return print(U(val < 0 ? -U(val) : U(val)));
} else if constexpr (is_integral_v<T2> && is_unsigned_v<T2>) {
T2 val2 = val;
array<char, 64> tmp;
char* tptr = end(tmp);
while (val2 >= 10'000)
tptr -= 4, memcpy(tptr, &DIGITS[val2 % 10'000][0], 4), val2 /= T2(10'000);
int d = (val2 >= 100 ? (val2 >= 1000 ? 4 : 3) : (val2 >= 10 ? 2 : 1));
memcpy(optr, &DIGITS[val2][4 - d], d);
memcpy(optr + d, tptr, end(tmp) - tptr);
optr += d + int(end(tmp) - tptr);
} else if constexpr (is_floating_point_v<T2>)
optr += sprintf(optr, "%.30Lf", (long double)val);
else if constexpr (is_convertible_v<T, string_view>) {
string_view sv(val);
if (sz(sv) + 1 <= end(obuf) - optr)
memcpy(optr, data(sv), sz(sv)), optr += sz(sv);
else {
flush();
for (auto *p = data(sv), *pe = p + sz(sv); p != pe; p += write(STDOUT_FILENO, p, pe - p));
}
} else if constexpr (is_base_of_v<cp_lib_modint::ModIntTag, T2>)
return print(decltype(T2::mod())(val));
else if constexpr (cp_lib_type_meta::is_tuple_like<T2> && !is_std_array<T2>)
return apply([](auto&&... items) { (print(items), ...); }, forward<T>(val));
else {
trav(item, val)
print(item);
return;
}
*optr++ = ' ';
}
template <class T>
void read(T& val) {
auto skip_ws = [] {
do {
for (; iptr != iend && *iptr <= ' '; ++iptr);
if (iend - iptr < 64)
refill();
} while (*iptr <= ' ');
};
auto read_other = [&](auto other) {
read(other);
return other;
};
if constexpr (is_same_v<T, char>)
skip_ws(), val = *iptr++;
else if constexpr (is_same_v<T, bool> || is_same_v<T, vector<bool>::reference>) {
val = bool(read_other(uint8_t()));
} else if constexpr (is_base_of_v<cp_lib_modint::ModIntTag, T>) {
val = T(read_other(ll()));
} else if constexpr (is_integral_v<T>) {
skip_ws();
if (is_signed_v<T> && *iptr == '-')
++iptr, val = T(-read_other(make_unsigned_t<T>()));
else
for (val = 0; iptr != iend && *iptr > ' '; val = T(10 * val + (*iptr++ & 15)));
} else if constexpr (is_floating_point_v<T>)
skip_ws(), val = T(strtold(iptr, &iptr));
else if constexpr (is_same_v<T, string>) {
skip_ws();
val.clear();
do {
auto* after = find_if(iptr, iend, [](char c) { return c <= ' '; });
val.append(iptr, after);
if ((iptr = after) != iend)
break;
refill();
} while (iptr != iend);
} else if constexpr (cp_lib_type_meta::is_tuple_like<T> && !is_std_array<T>)
apply([](auto&... items) { (read(items), ...); }, val);
else
trav(item, val)
read(item);
}
}
using cp_lib_io::flush;
template <class... Args>
void print(Args&&... args) { (cp_lib_io::print(forward<Args>(args)), ...); }
template <class... Args>
void println(Args&&... args) {
if (sizeof...(Args))
(cp_lib_io::print(forward<Args>(args)), ...), *(cp_lib_io::optr - 1) = '\n';
else
print('\n'), --cp_lib_io::optr;
}
template <class... Args>
void read(Args&... args) { (cp_lib_io::read(args), ...); }
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 n ? floor_log2(n) + !is_pow2(n) : 0; }
namespace cp_lib_rmq {
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, cp_lib_rmq::minmax<T, false>>;
template <class T>
using Rmaxq = SparseTable<T, cp_lib_rmq::minmax<T, true>>;
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(move(map_)) {}
Graph(const A& adj_, M map_) : Graph(adj_, sz(adj_), move(map_)) {}
Graph(const A& adj_, int n_) : Graph(adj_, n_, identity()) {}
explicit Graph(const A& adj_) : Graph(adj_, identity()) {}
};
template <class A> Graph(const A&, int) -> Graph<A, identity>;
template <class A> Graph(const A&) -> Graph<A, identity>;
struct LowestCommonAncestor {
vector<int> time, euler;
Rmq<int> rmq;
template <class G, class = enable_if_t<!is_same_v<LowestCommonAncestor, remove_cvref_t<G>>>>
LowestCommonAncestor(G&& graph, int root = 0) {
auto [adj, n, to] = Graph(forward<G>(graph));
if (!n) return;
time = vector(n, -1);
vector<int> d;
auto dfs = [&, t=1, &adj=adj, &to=to](int v, int p, int tp, auto&& self) mutable -> void {
euler.push_back(p);
d.push_back(tp);
time[v] = t++;
trav(e, adj[v])
if (to(e) != p)
self(to(e), v, time[v], self);
};
dfs(root, -1, 0, dfs);
rep(i, n)
if (time[i] == -1)
dfs(i, -1, 0, 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;
auto av = lca(a, v), bv = lca(b, v), ab = lca(a, b);
return av != -1 && bv != -1 && ab != -1 && minmax(av, bv) == minmax(v, ab);
}
bool is_ancestor(int u, int v) const { return lca(u, v) == u; }
};
template <class A, class M>
struct NewGraph {
A& adj;
int n;
M map;
using Mapped = decltype(declval<M>()(*begin(declval<A>()[0])));
NewGraph(A& adj_, M map_) : adj(adj_), n(sz(adj)), map(move(map_)) {}
explicit NewGraph(A& adj_) : NewGraph(adj_, identity()) {}
};
template <class A> NewGraph(A&) -> NewGraph<A, identity>;
template <class G, class OnComp>
void biconnected_components(G&& graph, OnComp&& on_comp) {
auto [adj, n, map] = NewGraph(forward<G>(graph));
auto normalize = [&](auto mapped) {
if constexpr(is_convertible_v<int, decltype(mapped)>)
return pair(int(mapped), 0);
else
return mapped;
};
vector idx(n, INF);
vector<pair<int, decltype(begin(adj[0]))>> stack;
auto dfs = [&, &adj = adj, &map = map](int v, pair<int, int> pe, auto&& self) -> int {
int up = idx[v] = sz(stack), cnt = 0;
for (auto it = begin(adj[v]); it != end(adj[v]); ++it) {
auto [v2, e] = normalize(map(*it));
if (pair(v2, e) == pe)
continue;
up = min(up, idx[v2]);
if (idx[v2] == INF || idx[v2] < idx[v])
stack.emplace_back(v, it);
if (idx[v2] != INF)
continue;
int up2 = self(v2, pair(v, e), self);
up = min(up, up2);
if (up2 >= idx[v]) {
auto cut_v = (pe.first == -1 && !cnt++ ? nullopt : optional(v));
on_comp(cut_v, begin(stack) + idx[v2] - 1, end(stack));
stack.resize(idx[v2] - 1);
}
}
return up;
};
rep(i, n)
if (idx[i] == INF)
dfs(i, pair(-1, 0), dfs);
}
template <class G>
vector<vector<int>> block_vertex_tree(G&& graph) {
NewGraph g(forward<G>(graph));
vector adj(g.n, vector<int>());
biconnected_components(g, [&](auto, auto it, auto it_end) {
int vc = sz(adj);
adj.emplace_back();
for (; it != it_end; ++it)
for (int v : {it->first, g.map(*it->second)})
if (!sz(adj[v]) || adj[v].back() != vc)
adj[v].push_back(vc), adj[vc].push_back(v);
});
return adj;
}
int main() {
// int n, m; read(n, m);
// vector adj(n, vector<pair<int, int>>());
// rep(i, m) {
// int u, v; read(u, v);
// adj[u].emplace_back(v, i);
// adj[v].emplace_back(u, i);
// }
// vector<vector<int>> bicomps;
// biconnected_components(adj, [&](auto, auto it, auto it_end) {
// auto& comp = bicomps.emplace_back();
// for (; it != it_end; ++it)
// comp.push_back(it->second->second);
// });
// println(sz(bicomps));
// trav(comp, bicomps)
// println(sz(comp), comp);
// int n, m; read(n, m);
// vector adj(n, vector<int>());
// rep(_, m) {
// int u, v; read(u, v);
// adj[u].push_back(v);
// adj[v].push_back(u);
// }
// set<int> cut_vertices;
// biconnected_components(adj, [&](auto cut_v, auto, auto) {
// if (cut_v)
// cut_vertices.emplace(*cut_v);
// });
// trav(v, cut_vertices)
// println(v);
// int n, m; read(n, m);
// vector w(n, 0);
// read(w);
// vector adj(n, vector<int>());
// rep(_, m) {
// int u, v; read(u, v); --u, --v;
// adj[u].push_back(v);
// adj[v].push_back(u);
// }
// auto bvt = block_vertex_tree(adj);
// int nt = sz(bvt);
// vector wsum(nt, 0ll);
// copy(all(w), begin(wsum));
// auto dfs = [&](int v, int p, auto&& self) -> void {
// trav(v2, bvt[v])
// if (v2 != p)
// self(v2, v, self), wsum[v] += wsum[v2];
// };
// dfs(0, -1, dfs);
// rep(i, n) {
// if (sz(bvt[i]) == 1) {
// println(wsum[0] - w[i]);
// continue;
// }
// ll mx = wsum[0] - wsum[i];
// trav(v, bvt[i])
// if (wsum[v] < wsum[i])
// mx = max(mx, wsum[v]);
// println(mx);
// }
int n, m; read(n, m);
vector adj(n, vector<int>());
rep(_, m) {
int u, v; read(u, v); --u, --v;
adj[u].push_back(v);
adj[v].push_back(u);
}
auto bvt = block_vertex_tree(adj);
int nt = sz(bvt);
LowestCommonAncestor lca(bvt);
vector depth(nt, 0);
auto dfs = [&](int v, int p, auto&& self) -> void {
trav(v2, bvt[v])
if (v2 != p)
depth[v2] = depth[v] + 1, self(v2, v, self);
};
dfs(0, -1, dfs);
int q; read(q);
while (q--) {
int u, v; read(u, v); --u, --v;
int d = depth[u] + depth[v] - 2 * depth[lca.lca(u, v)];
println(u == v ? 0 : (d - 2) / 2);
}
}
Felerius