結果
問題 |
No.1326 ふたりのDominator
|
ユーザー |
![]() |
提出日時 | 2025-09-12 11:48:39 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 332 ms / 2,000 ms |
コード長 | 6,823 bytes |
コンパイル時間 | 10,514 ms |
コンパイル使用メモリ | 294,892 KB |
実行使用メモリ | 33,948 KB |
最終ジャッジ日時 | 2025-09-12 11:48:56 |
合計ジャッジ時間 | 15,395 ms |
ジャッジサーバーID (参考情報) |
judge / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 24 |
ソースコード
#include <bits/stdc++.h> using namespace std; using ll = long long; using pll = pair<ll, ll>; #define vc vector using vl = vc<ll>; #define ov(a, b, c, name, ...) name #define rep2(i, l, r) for(ll i = (l); i < ll(r); i++) #define rep1(i, n) rep2(i, 0, n) #define rep(...) ov(__VA_ARGS__, rep2, rep1)(__VA_ARGS__) #define fec(...) for(const auto& __VA_ARGS__) #define per(i, a, b) for(ll i = ll(a) - 1; i >= ll(b); i--) #define ALL(x) begin(x), end(x) #define SZ(x) (ll) size(x) #define LB(v, x) (lower_bound(ALL(v), x) - begin(v)) #define eb emplace_back bool chmin(auto& a, auto b) { return a > b ? a = b, 1 : 0; } bool chmax(auto& a, auto b) { return a < b ? a = b, 1 : 0; } const ll INF = ll(4e18) + 100; void printvec(const auto& v) { for(auto it = begin(v); it != end(v); it++) cout << *it << " "; cout << endl; } #ifdef LOCAL #define local(...) __VA_ARGS__ #else #define local(...) #endif template<typename G> struct LL { int n; const G g; vc<int> ord, low, arti; vector<pll> bridge; LL(G g) : n(g.size()), g(g), ord(n, -1), low(n, -1) { int k = 0; rep(i, n) { if(ord[i] == -1) k = dfs(i, k, -1); } } int dfs(int x, int k, int p) { low[x] = ord[x] = k++; int cnt = 0; bool is_arti = false, second = false; fec(e : g[x]) { if(ord[e] == -1) { cnt++; k = dfs(e, k, x); chmin(low[x], low[e]); is_arti |= (p != -1) && (low[e] >= ord[x]); if(ord[x] < low[e]) bridge.eb(minmax<ll>(x, e)); } else if(e != p or second) { chmin(low[x], ord[e]); } else { second = true; } } is_arti |= p == -1 && cnt > 1; if(is_arti) arti.eb(x); return k; } }; // depends on lowlink // 二重連結成分: 二重連結 (どの頂点を削除しても連結のまま) かつ極大な部分グラフ // bc には辺集合が入る // 辺はちょうど一つの bcc に属するが、頂点は複数の bcc に属することもある // bc.size() は **孤立点以外の** bcc の個数 template<typename G> struct BCC : LL<G> { vc<bool> used; vc<vc<pll>> bc; vc<pll> tmp; using L = LL<G>; using L::g; using L::low; using L::ord; BCC(G g) : L(g) { used.assign(g.size(), 0); rep(i, used.size()) if(!used[i]) dfs(i, -1); } void dfs(int x, int p) { used[x] = true; fec(e : g[x]) { if(e == p) continue; if(!used[e] || ord[e] < ord[x]) tmp.eb(minmax<ll>(x, e)); if(used[e]) continue; dfs(e, x); if(low[e] >= ord[x]) { bc.eb(); while(true) { auto p = tmp.back(); bc.back().eb(p); tmp.pop_back(); if(p == (pll)minmax<ll>(x, e)) break; } } } } }; // depends on lowlink, bcc // 関節点 (an 個) と二重連結成分 (bn 個) からなる森 (tree に格納) // 頂点番号は [0, an) と [an, an+bn) // vtoi[v]: もとのグラフの頂点 v → BCT の頂点 i // (関節点は関節点、それ以外は属する唯一の二重連結成分) // 孤立点は -1 になるので注意 template <class G> struct BCT : BCC<G> { using B = BCC<G>; using B::bc; using B::L::arti; vc<vc<int>> tree; vc<int> vtoi; int an, bn; BCT(const G &g) : B(g) { an = arti.size(), bn = bc.size(); tree.resize(an + bn); vtoi.resize(g.size(), -1); rep(i, an) vtoi[arti[i]] = i; rep(j, bn) fec([u, v] : bc[j]) fec(w : {u, v}) { int &i = vtoi[w]; if(0 <= i && i < an) { if (tree[i].empty() || tree[i].back() != an + j) { tree[i].eb(an + j), tree[an + j].eb(i); } } else i = an + j; } } }; template<class G> struct HLD { int n; G& g; vc<int> sub, in, out, head, rev, par, d; HLD(G& g, int root = 0) : n(g.size()), g(g), sub(n), in(n), out(n), head(n), rev(n), par(n), d(n) { int t = 0; head[root] = 0; dfs1(root, -1); dfs2(root, -1, t); } void dfs1(int x, int p) { par[x] = p; sub[x] = 1; if(g[x].size() and g[x][0] == p) swap(g[x][0], g[x].back()); for(auto &e : g[x]) { if(e == p) continue; d[e] = d[x] + 1; dfs1(e, x); sub[x] += sub[e]; if(sub[g[x][0]] < sub[e]) swap(g[x][0], e); } } void dfs2(int x, int p, int& t) { in[x] = t++; rev[in[x]] = x; fec(e : g[x]) { if(e == p) continue; head[e] = (g[x][0] == e ? head[x] : e); dfs2(e, x, t); } out[x] = t; } int la(int v, int k) { while(1) { int u = head[v]; if(in[v] - k >= in[u]) return rev[in[v] - k]; k -= in[v] - in[u] + 1; v = par[u]; } } int lca(int u, int v) { for(;; v = par[head[v]]) { if(in[u] > in[v]) swap(u, v); if(head[u] == head[v]) return u; } } template<typename T, typename Q, typename F> T query(int u, int v, const T& e, const Q& q, const F& f, bool edge = false) { T l = e, r = e; for(;; v = par[head[v]]) { if(in[u] > in[v]) swap(u, v), swap(l, r); if(head[u] == head[v]) break; l = f(q(in[head[v]], in[v] + 1), l); } return f(f(q(in[u] + edge, in[v] + 1), l), r); } int dist(int u, int v) { return d[u] + d[v] - 2 * d[lca(u, v)]; } int jump(int s, int t, int i) { if(!i) return s; int l = lca(s, t); int dst = d[s] + d[t] - d[l] * 2; if(dst < i) return -1; if(d[s] - d[l] >= i) return la(s, i); i -= d[s] - d[l]; return la(t, d[t] - d[l] - i); } }; int main() { ll N, M; cin >> N >> M; vc<vl> G(N); rep(i, M) { ll u, v; cin >> u >> v; u--, v--; G.at(u).eb(v); G.at(v).eb(u); } BCT bct(G); auto& H = bct.tree; ll K = bct.an + bct.bn; local(rep(i, K) printvec(H.at(i))); local(printvec(bct.vtoi)); HLD hld(H); vl dp(K); dp.at(0) = 0 < bct.an; queue<ll> que; que.push(0); while(!que.empty()) { ll v = que.front(); que.pop(); fec(c : H.at(v)) { if(hld.par.at(v) == c) continue; dp.at(c) = dp.at(v) + (c < bct.an); que.push(c); } } local(printvec(dp)); ll Q; cin >> Q; rep(_, Q) { ll u, v; cin >> u >> v; u--, v--; if(u == v) { cout << 0 << "\n"; continue; } ll i = bct.vtoi.at(u), j = bct.vtoi.at(v); ll k = hld.lca(i, j); local(cout << u << " " << v << " " << i << " " << j << " " << k << endl); ll ans = dp.at(i) + dp.at(j) - dp.at(k) - (k == 0 ? 0 : dp.at(hld.par.at(k))) - (i < bct.an) - (j < bct.an); cout << ans << "\n"; } }