complete implemenation of bsb: need more debugging

This commit is contained in:
2025-11-10 05:55:26 +09:00
parent dd80e1ea1e
commit 28c4b5c61f
4 changed files with 399 additions and 68 deletions

View File

@@ -1,6 +1,7 @@
SHELL = /bin/bash SHELL = /bin/bash
CXX = g++ # CXX = g++
CXX = clang++
SRC_DIR = src SRC_DIR = src
GEN_DIR = generator GEN_DIR = generator

248
src/bsb/bsb.hpp Normal file
View File

@@ -0,0 +1,248 @@
#ifndef BSB_HPP
#define BSB_HPP
#include <algorithm>
#include <boost/heap/fibonacci_heap.hpp>
#include <cassert>
#include <cmath>
#include <list>
#include <map>
#include <optional>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>
namespace GMS {
using namespace std;
using ll = unsigned long long;
template <typename KEY, typename VALUE>
class L33 {
private:
using KV = pair<KEY, VALUE>;
using KV_LIST = vector<KV>;
using K_LIST = vector<KEY>;
using BLOCK = list<KV>;
using BLOCK_LIST = list<BLOCK>;
using ITEM = pair<VALUE, typename BLOCK_LIST::iterator>;
using ITEM_LIST = list<ITEM>;
const ll M;
const VALUE B;
BLOCK_LIST blocks;
ITEM_LIST D0, D1;
unordered_map<
KEY, tuple<bool, typename ITEM_LIST::iterator,
typename BLOCK_LIST::iterator, typename BLOCK::iterator> >
ptr;
map<VALUE, typename ITEM_LIST::iterator> UB;
void Delete(const KEY& a, optional<VALUE> b = std::nullopt) {
assert(ptr.count(a));
auto [d01, it_ILIST, it_BLIST, it_B] = ptr[a];
ptr.erase(a);
assert(!b || it_B->second == b.value());
it_BLIST->erase(it_B);
if (it_BLIST->size() == 0) {
blocks.erase(it_BLIST);
if (d01 == 0)
D0.erase(it_ILIST);
else {
UB.erase(it_ILIST->first);
D1.erase(it_ILIST);
if (D1.empty()) {
auto it_BLIST = blocks.emplace(blocks.end());
auto it_ILIST = D1.emplace(D1.end(), B, it_BLIST);
UB[B] = it_ILIST;
}
}
}
}
void split(bool d01, typename ITEM_LIST::iterator it_ILIST) {
auto it_BLIST = it_ILIST->second;
BLOCK& B = *it_BLIST;
if (B.size() <= M) return;
const ll L = B.size() / 2;
KV_LIST S;
S.reserve(B.size());
for (auto& item : B) {
ptr.erase(item.first);
S.emplace_back(std::move(item));
}
auto nth = S.begin();
advance(nth, L - 1);
nth_element(S.begin(), nth, S.end());
advance(nth, 1);
BLOCK X, Y;
auto it = S.begin();
while (it != nth) {
X.emplace_back(std::move(*it)), ++it;
}
while (it != S.end()) Y.emplace_back(std::move(*it)), ++it;
VALUE ubx = Y.front().second;
for (auto& [a, b] : Y) ubx = min(ubx, b);
auto it_BLIST_X = blocks.emplace(it_BLIST, std::move(X));
auto it_BLIST_Y = blocks.emplace(it_BLIST, std::move(Y));
blocks.erase(it_BLIST);
auto it_ILIST_Y = it_ILIST;
it_ILIST->second = it_BLIST_Y;
auto it_ILIST_X = (d01 ? D0 : D1).insert(it_ILIST_Y, {ubx, it_BLIST_X});
if (d01) UB[ubx] = it_ILIST_X;
for (auto it = it_BLIST_X->begin(); it != it_BLIST_X->end(); it++) {
const auto [a, b] = *it;
ptr[a] = {d01, it_ILIST_X, it_BLIST_X, it};
}
for (auto it = it_BLIST_Y->begin(); it != it_BLIST_Y->end(); it++) {
const auto [a, b] = *it;
ptr[a] = {d01, it_ILIST_Y, it_BLIST_Y, it};
}
split(d01, it_ILIST_X);
split(d01, it_ILIST_Y);
}
public:
L33(ll _M, VALUE _B) : M(_M), B(_B) {
auto it_BLIST = blocks.emplace(blocks.end());
auto it_ILIST = D1.emplace(D1.end(), B, it_BLIST);
UB[B] = it_ILIST;
}
void Insert(const KEY& a, const VALUE& b) {
if (ptr.count(a)) {
auto [d01, it_ILIST, it_BLIST, it_B] = ptr[a];
if (it_B->second <= b) return;
Delete(a);
}
auto it_ILIST = UB.lower_bound(b)->second;
auto it_BLIST = it_ILIST->second;
auto it_B = it_BLIST->emplace(it_BLIST->end(), a, b);
ptr[a] = {1, it_ILIST, it_BLIST, it_B};
split(1, it_ILIST);
}
void BatchPrepend(const KV_LIST& L) {
if (L.size() == 0) return;
BLOCK tmp;
optional<VALUE> u = nullopt;
for (auto [a, b] : L) {
if (ptr.count(a)) {
auto [d01, it_ILIST, it_BLIST, it_B] = ptr[a];
if (it_B->second <= b) continue;
Delete(a);
}
if (!u)
u = b;
else
u = max(u.value(), b);
tmp.push_back({a, b});
}
if (u == nullopt) return;
auto it_BLIST = blocks.emplace(blocks.end(), std::move(tmp));
auto it_ILIST = D0.emplace(D0.begin(), u.value(), it_BLIST);
split(0, it_ILIST);
}
pair<VALUE, K_LIST> Pull() {
BLOCK S0, S1;
auto it = D0.begin();
while (S0.size() < M + 1 && it != D0.end()) {
S0.splice(S0.end(), *it->second);
blocks.erase(it->second);
it = D0.erase(it);
}
it = D1.begin();
while (S1.size() < M + 1 && it != D1.end()) {
S1.splice(S0.end(), *it->second);
blocks.erase(it->second);
UB.erase(it->first);
it = D1.erase(it);
}
KV_LIST S;
S.reserve(S0.size() + S1.size());
for (auto& item : S0) S.emplace_back(std::move(item));
for (auto& item : S1) S.emplace_back(std::move(item));
for (auto [a, b] : S) ptr.erase(a);
if (D1.empty()) {
auto it_BLIST = blocks.emplace(blocks.end());
auto it_ILIST = D1.emplace(D1.end(), B, it_BLIST);
UB[B] = it_ILIST;
}
if (S.size() <= M) {
K_LIST s;
s.reserve(S.size());
for (auto [a, b] : S) s.push_back(a);
return {B, s};
}
auto nth = S.begin();
std::advance(nth, M - 1);
std::nth_element(S.begin(), nth, S.end());
KV_LIST R(make_move_iterator(nth + 1), make_move_iterator(S.end()));
S.resize(M);
VALUE x = R.front().second;
for (auto [a, b] : R) x = min(x, b);
BatchPrepend(R);
K_LIST s;
s.reserve(S.size());
for (auto [a, b] : S) s.push_back(a);
return {x, s};
}
bool empty() const { return ptr.empty(); }
};
} // namespace GMS
#endif

View File

@@ -1,95 +1,171 @@
#include <cassert> #include <cassert>
#include <cmath>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <iterator>
#include <limits> #include <limits>
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <cmath> #include "bsb.hpp"
#include <optional>
#include <unordered_set>
#include <unordered_map>
#include <boost/heap/fibonacci_heap.hpp>
using namespace std; using namespace std;
using namespace GMS;
using DIST = tuple<double, ll, ll>;
using DIST_LIST = vector<DIST>;
using Item = pair<DIST, ll>;
using Fiboheap =
boost::heap::fibonacci_heap<Item, boost::heap::compare<greater<Item> > >;
using ll = long long;
using Edge = tuple<ll, ll, double>; using Edge = tuple<ll, ll, double>;
using ADJ_LIST = vector<vector<pair<ll, double> > >; using ADJ_LIST = vector<vector<pair<ll, double> > >;
using Item = pair<double, ll>;
using Fiboheap = boost::heap::fibonacci_heap<Item, boost::heap::compare<greater<Item> > >;
const double INF = numeric_limits<double>::infinity(); const double INF = numeric_limits<double>::infinity();
pair<vector<ll>, vector<ll> > FindPivots(double B, vector<ll> S, const ADJ_LIST& adj, vector<double>& dist, ll k, ll t)
{
unordered_set<ll> U;
for(auto i: S) U.insert(i);
unordered_set<ll> bef = U; bool relex(ll s, DIST& ds, double len, ll i, DIST& di) {
for(ll tr = 1; tr <= k; tr++) DIST tmp = {get<0>(ds) + len, get<1>(ds) + 1, s};
{
if (di >= tmp) {
di = tmp;
return true;
}
return false;
}
pair<vector<ll>, vector<ll> > FindPivots(DIST B, vector<ll> S,
const ADJ_LIST& adj, DIST_LIST& dist,
const ll k, const ll t) {
unordered_set<ll> W;
for (auto i : S) W.insert(i);
unordered_set<ll> bef = W;
for (ll tr = 1; tr <= k; tr++) {
unordered_set<ll> st; unordered_set<ll> st;
for(auto s:bef) for (auto s : bef) {
{ for (auto [i, len] : adj[s]) {
for(auto [i, len] : adj[s]) if (relex(s, dist[s], len, i, dist[i])) {
{ if (dist[i] < B) st.insert(i);
if(dist[i] >= dist[s] + len)
{
} }
} }
} }
for(auto i:st) U.insert(i); for (auto i : st) W.insert(i);
swap(st, bef); swap(st, bef);
if (W.size() > k * S.size()) return {S, vector<ll>(W.begin(), W.end())};
} }
unordered_map<ll, ll> par, cnt;
function<int(int)> root = [&W, &par, &cnt, &dist, &root](int s) -> int {
int p = get<2>(dist[s]);
if (!W.count(p)) {
cnt[s]++;
return s;
}
if (par.count(s)) {
cnt[par[s]]++;
return par[s];
}
par[s] = root(p);
cnt[par[s]]++;
return par[s];
};
for (auto i : W) root(i);
vector<ll> P;
for (auto [i, c] : cnt)
if (c >= k) P.push_back(i);
return {P, vector<ll>(W.begin(), W.end())};
} }
pair<double, vector<ll> > BMSSP(ll l, vector<ll> S, double B, const ADJ_LIST& adj, vector<double>& dist, ll k, ll t) pair<DIST, unordered_set<ll> > BMSSP(ll l, vector<ll> S, DIST B, const ADJ_LIST& adj,
{ DIST_LIST& dist, const ll k, const ll t) {
assert(S.size() <= 1LL<<(l*t)); assert(S.size() <= (1uLL << (l * t)));
if(l == 0) if (l == 0) {
{
ll s = S.front(); ll s = S.front();
vector<ll> U; vector<ll> U;
Fiboheap pq; unordered_map<ll, optional<Fiboheap::handle_type> > handle; Fiboheap pq;
unordered_map<ll, optional<Fiboheap::handle_type> > handle;
handle[s] = pq.push({dist[s], s}); handle[s] = pq.push({dist[s], s});
while(!pq.empty() && U.size() < k+1) while (!pq.empty() && U.size() < k + 1) {
{ auto [du, u] = pq.top();
auto [du, u] = pq.top(); pq.pop(); pq.pop();
handle[u] = nullopt; handle[u] = nullopt;
U.push_back(u); U.push_back(u);
for(auto [v, len] : adj[u]) for (auto [v, len] : adj[u]) {
{ if (relex(u, dist[u], len, v, dist[v]) && dist[v] < B &&
if(dist[u]+len >= dist[v] && dist[u]+len < B && (!handle.count(v) || handle[v] != nullopt)) (!handle.count(v) || handle[v] != nullopt)) {
{ if (handle.count(v))
dist[v] = dist[u] + len; pq.increase(handle[v].value(), {dist[v], v});
if(handle.count(v)) pq.increase(handle[v].value(), {dist[v], v}); else
else handle[v] = pq.push({dist[v], v}); handle[v] = pq.push({dist[v], v});
} }
} }
} }
if(U.size() <= k) return {B, U}; DIST B_ = dist[U.back()];
double B_ = dist[U.front()];
for(auto i:U) B_ = max(B_, dist[i]);
return {B_, U}; unordered_set<ll> u(make_move_iterator(U.begin()), make_move_iterator(U.end()));
if (U.size() <= k) return {B, u};
return {B_, u};
} }
double B_ = B;
vector<ll> U = S;
auto [P, W] = FindPivots(B, S, adj, dist, k, t); auto [P, W] = FindPivots(B, S, adj, dist, k, t);
const ll M = (1uLL << ((l - 1) * t));
L33<ll, DIST> D(M, B);
for (auto i : P) D.Insert(i, dist[i]);
const ll LIMIT = k * (1uLL << (l * t));
unordered_set<ll> U; DIST B_;
while (U.size() < LIMIT && !D.empty()) {
auto [Bi, Si] = D.Pull();
auto [Bi_, Ui] = BMSSP(l - 1, Si, Bi, adj, dist, k, t);
B_ = Bi_;
unordered_set<ll> K;
for(auto u : Ui) for(auto [v, len] : adj[u])
{
if(relex(u, dist[u], len, v, dist[v]))
{
if(Bi <= dist[v] && dist[v] < B) D.Insert(v, dist[v]);
else if(Bi_ <= dist[v] && dist[v] < Bi) K.insert(v);
}
}
for(auto s:Si) if(Bi_ <= dist[s] && dist[s] < Bi)
K.insert(s);
U.merge(Ui);
vector<pair<ll, DIST> > K_; K_.reserve(K.size());
for(auto k:K) K_.push_back({k, dist[k]});
D.BatchPrepend(K_);
}
B_ = min(B_, B);
for(auto s:W) if(dist[s] < B_) U.insert(s);
return {B_, U}; return {B_, U};
} }
@@ -112,41 +188,46 @@ int main() {
vector<vector<ll> > renum(n + 1); vector<vector<ll> > renum(n + 1);
ll c = 0; ll c = 0;
auto get = [&c, &renum](ll x) -> ll { auto get_renum = [&c, &renum](ll x) -> ll {
renum[x].push_back(++c); renum[x].push_back(++c);
return c; return c;
}; };
ADJ_LIST adj(2*m + 1); ADJ_LIST adj(2 * m + 1);
for (auto [s, e, len] : edges) { for (auto [s, e, len] : edges) {
adj[get(s)].emplace_back(get(e), len); adj[get_renum(s)].emplace_back(get_renum(e), len);
} }
assert(c == 2*m); assert(c == 2 * m);
for (ll i = 1; i <= n; i++) { for (ll i = 1; i <= n; i++) {
if (renum[i].size() <= 1) continue; if (renum[i].size() <= 1) continue;
ll k = renum[i].size(); ll k = renum[i].size();
for (ll s = 0; s < k; s++) { for (ll s = 0; s < k; s++) {
adj[renum[i][s]].emplace_back(renum[i][(s+1)%k], 0.0); adj[renum[i][s]].emplace_back(renum[i][(s + 1) % k], 0.0);
} }
} }
const ll k = floor(pow(log2(2*m), 1.0/3)); const ll k = floor(pow(log2(2 * m), 1.0 / 3));
const ll t = floor(pow(log2(2*m), 2.0/3)); const ll t = floor(pow(log2(2 * m), 2.0 / 3));
const ll l = ceil((log2(2*m)/t)); const ll l = ceil((log2(2 * m) / t));
const int s = 1; const int s = 1;
vector<double> dist(2*m+1, INF);
dist[s] = 1;
auto [B_, U] = BMSSP(l, {s}, INF, adj, dist, k, t); // distance,
DIST_LIST dist(2 * m + 1, {INF, INF, -1});
vector<double> ans(n+1, INF); dist[s] = {0, 0, -1};
for(ll i=1;i<=n;i++) if(!renum[i].empty()) ans[i] = dist[renum[i].front()];
const DIST Binf = {INF, -1, -1};
auto [B_, U] = BMSSP(l, {s}, Binf, adj, dist, k, t);
vector<double> ans(n + 1, INF);
for (ll i = 1; i <= n; i++)
if (!renum[i].empty()) ans[i] = get<0>(dist[renum[i].front()]);
cout << fixed << setprecision(15); cout << fixed << setprecision(15);
for (ll i = 1; i <= n; i++) cout << ans[i] << '\n'; for (ll i = 1; i <= n; i++) cout << ans[i] << '\n';

View File

@@ -9,7 +9,8 @@ using namespace std;
using ll = long long; using ll = long long;
using Item = pair<double, ll>; using Item = pair<double, ll>;
using Fiboheap = boost::heap::fibonacci_heap<Item, boost::heap::compare<greater<Item> > >; using Fiboheap =
boost::heap::fibonacci_heap<Item, boost::heap::compare<greater<Item> > >;
const double INF = numeric_limits<double>::infinity(); const double INF = numeric_limits<double>::infinity();