結果
問題 | No.2897 2集合間距離 |
ユーザー | 矢澤式WINTER |
提出日時 | 2024-09-20 22:53:03 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
WA
|
実行時間 | - |
コード長 | 19,700 bytes |
コンパイル時間 | 6,333 ms |
コンパイル使用メモリ | 336,648 KB |
実行使用メモリ | 119,760 KB |
最終ジャッジ日時 | 2024-09-20 22:53:22 |
合計ジャッジ時間 | 12,596 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | WA | - |
testcase_01 | WA | - |
testcase_02 | AC | 2 ms
5,376 KB |
testcase_03 | AC | 2 ms
5,376 KB |
testcase_04 | WA | - |
testcase_05 | AC | 2 ms
5,376 KB |
testcase_06 | AC | 2 ms
5,376 KB |
testcase_07 | AC | 2 ms
5,376 KB |
testcase_08 | AC | 2 ms
5,376 KB |
testcase_09 | WA | - |
testcase_10 | WA | - |
testcase_11 | AC | 2 ms
5,376 KB |
testcase_12 | AC | 4 ms
5,376 KB |
testcase_13 | AC | 5 ms
5,376 KB |
testcase_14 | AC | 19 ms
7,072 KB |
testcase_15 | AC | 36 ms
7,960 KB |
testcase_16 | AC | 660 ms
119,760 KB |
testcase_17 | AC | 633 ms
119,752 KB |
testcase_18 | AC | 659 ms
119,752 KB |
testcase_19 | AC | 632 ms
119,748 KB |
testcase_20 | AC | 656 ms
119,760 KB |
testcase_21 | WA | - |
testcase_22 | WA | - |
testcase_23 | WA | - |
ソースコード
#include <bits/stdc++.h> using namespace std; //*/ #include <atcoder/all> using namespace atcoder; // //*/ // #pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math") // #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") // #pragma GCC target("avx,avx2,fma") // #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma") #define rep(i,n) for(int i=0;i<n;i++) #define Rep(i,a,b) for(int i=a;i<b;i++) #define ALL(x) (x).begin(),(x).end() #define dbgv(x); for(auto now : x) cout << now << " "; cout << endl; //using p = pair<int,int>; using ll = long long; using ull = unsigned long long; //*/ template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; } template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; } typedef pair<int, int> pii; typedef pair<ll, ll> pll; typedef vector<ll> vll; typedef vector<int> vint; random_device rnd; mt19937 rng(rnd()); namespace nachia{ template<class Int = long long, class Int2 = long long> struct VecI2 { Int x, y; VecI2() : x(0), y(0) {} VecI2(std::pair<Int, Int> _p) : x(std::move(_p.first)), y(std::move(_p.second)) {} VecI2(Int _x, Int _y) : x(std::move(_x)), y(std::move(_y)) {} VecI2& operator+=(VecI2 r){ x+=r.x; y+=r.y; return *this; } VecI2& operator-=(VecI2 r){ x-=r.x; y-=r.y; return *this; } VecI2& operator*=(Int r){ x*=r; y*=r; return *this; } VecI2 operator+(VecI2 r) const { return VecI2(x+r.x, y+r.y); } VecI2 operator-(VecI2 r) const { return VecI2(x-r.x, y-r.y); } VecI2 operator*(Int r) const { return VecI2(x*r, y*r); } VecI2 operator-() const { return VecI2(-x, -y); } Int2 operator*(VecI2 r) const { return Int2(x) * Int2(r.x) + Int2(y) * Int2(r.y); } Int2 operator^(VecI2 r) const { return Int2(x) * Int2(r.y) - Int2(y) * Int2(r.x); } bool operator<(VecI2 r) const { return x < r.x || (!(r.x < x) && y < r.y); } Int2 norm() const { return Int2(x) * Int2(x) + Int2(y) * Int2(y); } static bool compareYX(VecI2 a, VecI2 b){ return a.y < b.y || (!(b.y < a.y) && a.x < b.x); } static bool compareXY(VecI2 a, VecI2 b){ return a.x < b.x || (!(b.x < a.x) && a.y < b.y); } bool operator==(VecI2 r) const { return x == r.x && y == r.y; } bool operator!=(VecI2 r) const { return x != r.x || y != r.y; } }; } // namespace nachia namespace nachia{ template<class Elem> class CsrArray{ public: struct ListRange{ using iterator = typename std::vector<Elem>::iterator; iterator begi, endi; iterator begin() const { return begi; } iterator end() const { return endi; } int size() const { return (int)std::distance(begi, endi); } Elem& operator[](int i) const { return begi[i]; } }; struct ConstListRange{ using iterator = typename std::vector<Elem>::const_iterator; iterator begi, endi; iterator begin() const { return begi; } iterator end() const { return endi; } int size() const { return (int)std::distance(begi, endi); } const Elem& operator[](int i) const { return begi[i]; } }; private: int m_n; std::vector<Elem> m_list; std::vector<int> m_pos; public: CsrArray() : m_n(0), m_list(), m_pos() {} static CsrArray Construct(int n, std::vector<std::pair<int, Elem>> items){ CsrArray res; res.m_n = n; std::vector<int> buf(n+1, 0); for(auto& [u,v] : items){ ++buf[u]; } for(int i=1; i<=n; i++) buf[i] += buf[i-1]; res.m_list.resize(buf[n]); for(int i=(int)items.size()-1; i>=0; i--){ res.m_list[--buf[items[i].first]] = std::move(items[i].second); } res.m_pos = std::move(buf); return res; } static CsrArray FromRaw(std::vector<Elem> list, std::vector<int> pos){ CsrArray res; res.m_n = pos.size() - 1; res.m_list = std::move(list); res.m_pos = std::move(pos); return res; } ListRange operator[](int u) { return ListRange{ m_list.begin() + m_pos[u], m_list.begin() + m_pos[u+1] }; } ConstListRange operator[](int u) const { return ConstListRange{ m_list.begin() + m_pos[u], m_list.begin() + m_pos[u+1] }; } int size() const { return m_n; } int fullSize() const { return (int)m_list.size(); } }; } // namespace nachia namespace nachia{ // Int3 must be able to handle the value range : // |x| <= | (any input - any input) ** 4 * 12 | template<class Int = long long, class Int2 = long long, class Int3 = Int2> class DelaunayTriangulation { public: using GPos2 = VecI2<Int, Int2>; struct Circumcenter { Int3 x; Int3 y; Int2 d; static Circumcenter From3Points(GPos2 p1, GPos2 p2, GPos2 p3){ GPos2 dp1 = p2 - p1; GPos2 dp2 = p3 - p1; Int2 d1 = dp1.norm(); Int2 d2 = dp2.norm(); Int2 w = dp1 ^ dp2; w += w; Int3 px = (Int3(dp2.y) * Int3(d1) - Int3(dp1.y) * Int3(d2)) + Int3(w) * Int3(p1.x); Int3 py = (Int3(dp1.x) * Int3(d2) - Int3(dp2.x) * Int3(d1)) + Int3(w) * Int3(p1.y); return { px, py, w }; } }; struct Edge { int to; int ccw; int cw; int rev; bool enabled = false; }; private: static int isDinOABC(GPos2 a, GPos2 b, GPos2 c, GPos2 d){ a = a - d; b = b - d; c = c - d; auto val = Int3(b^c) * Int3(a.norm()) + Int3(c^a) * Int3(b.norm()) + Int3(a^b) * Int3(c.norm()); return val > Int3(0) ? 1 : 0; } int getOpenAddress(){ if(openAddress.empty()){ edges.push_back({}); return (int)edges.size() - 1; } int res = openAddress.back(); openAddress.pop_back(); return res; } std::pair<int, int> newEdge(int u, int v){ int euv = getOpenAddress(); int evu = getOpenAddress(); edges[euv].ccw = edges[euv].cw = euv; edges[evu].ccw = edges[evu].cw = evu; edges[euv].to = v; edges[evu].to = u; edges[euv].rev = evu; edges[evu].rev = euv; edges[euv].enabled = true; edges[evu].enabled = true; return { euv, evu }; } void eraseSingleEdge(int e){ int eccw = edges[e].ccw; int ecw = edges[e].cw; edges[eccw].cw = ecw; edges[ecw].ccw = eccw; edges[e].enabled = false; } void eraseEdgeBidirectional(int e){ int ex = edges[e].rev; eraseSingleEdge(e); eraseSingleEdge(ex); openAddress.push_back(e); openAddress.push_back(ex); } void insertCcwAfter(int e, int x){ int xccw = edges[x].ccw; edges[e].ccw = xccw; edges[xccw].cw = e; edges[e].cw = x; edges[x].ccw = e; } void insertCwAfter(int e, int x){ int xcw = edges[x].cw; edges[e].cw = xcw; edges[xcw].ccw = e; edges[e].ccw = x; edges[x].cw = e; } // move from ab to ac ... is this ccw? int isCcw(int a, int b, int c) const { auto ab = pos[b] - pos[a]; auto ac = pos[c] - pos[a]; auto cp = ab ^ ac; if(0 < cp) return 1; if(cp < 0) return -1; return 0; } std::pair<int, int> goNext(int , int ea){ int ap = edges[ea].to; int eap = edges[edges[ea].rev].ccw; return { ap, eap }; } std::pair<int, int> goPrev(int , int ea){ int ap = edges[edges[ea].cw].to; int eap = edges[edges[ea].cw].rev; return { ap, eap }; } std::tuple<int, int, int, int> goBottom(int a, int ea, int b, int eb){ while(true){ auto [ap, eap] = goPrev(a, ea); if(isCcw(b, a, ap) > 0){ std::tie(a, ea) = { ap, eap }; continue; } auto [bp, ebp] = goNext(b, eb); if(isCcw(a, b, bp) < 0){ std::tie(b, eb) = { bp, ebp }; continue; } break; } return { a, ea, b, eb }; } std::pair<int, int> getMaximum(int a, int ea, bool toMin){ std::pair<int, int> ans = { a, ea }; int p = a, ep = ea; do { std::tie(p, ep) = goNext(p, ep); if(toMin) ans = std::min(ans, std::make_pair(p, ep)); else ans = std::max(ans, std::make_pair(p, ep)); } while(ep != ea); return ans; } bool isDinOABC(int a, int b, int c, int d){ return isDinOABC(pos[a], pos[b], pos[c], pos[d]); } std::pair<int, int> dfs(int a, int ea, int b, int eb){ std::tie(a, ea) = getMaximum(a, ea, false); std::tie(b, eb) = getMaximum(b, eb, true); auto [al, eal, bl, ebl] = goBottom(a, ea, b, eb); auto [bu, ebu, au, eau] = goBottom(b, eb, a, ea); ebl = edges[ebl].cw; ebu = edges[ebu].cw; auto [abl, bal] = newEdge(al, bl); insertCwAfter(abl, eal); insertCcwAfter(bal, ebl); if(al == au) eau = abl; if(bl == bu) ebu = bal; int ap = al, eap = eal; int bp = bl, ebp = ebl; while(ap != au || bp != bu){ int a2 = edges[eap].to; int b2 = edges[ebp].to; int nxeap = edges[eap].ccw; int nxebp = edges[ebp].cw; if(eap != eau && nxeap != abl){ int a1 = edges[nxeap].to; if(isDinOABC(ap, bp, a2, a1)){ eraseEdgeBidirectional(eap); eap = nxeap; continue; } } if(ebp != ebu && nxebp != bal){ int b1 = edges[nxebp].to; if(isDinOABC(b2, ap, bp, b1)){ eraseEdgeBidirectional(ebp); ebp = nxebp; continue; } } bool chooseA = ebp == ebu; if(eap != eau && ebp != ebu){ if(isCcw(ap, bp, b2) < 0) chooseA = true; else if(isCcw(a2, ap, bp) < 0) chooseA = false; else chooseA = isDinOABC(ap, bp, b2, a2); } if(chooseA){ nxeap = edges[edges[eap].rev].ccw; auto [hab, hba] = newEdge(a2, bp); insertCwAfter(hab, nxeap); insertCcwAfter(hba, ebp); eap = nxeap; ap = a2; } else { nxebp = edges[edges[ebp].rev].cw; auto [hba, hab] = newEdge(b2, ap); insertCcwAfter(hba, nxebp); insertCwAfter(hab, eap); ebp = nxebp; bp = b2; } } return { al, abl }; } std::pair<int, int> solveRange(int l, int r){ if(r - l == 2){ int u = l; int v = l + 1; auto [uv, vu] = newEdge(u, v); return { u, uv }; } if(r - l == 3){ int u = l; int v = l + 1; int w = l + 2; auto [uv, vu] = newEdge(u, v); auto [vw, wv] = newEdge(v, w); int ccw = isCcw(u, v, w); if(ccw == 0){ insertCcwAfter(vu, vw); } if(ccw > 0){ auto [uw, wu] = newEdge(u, w); insertCwAfter(uv, uw); insertCwAfter(vw, vu); insertCwAfter(wu, wv); return { u, uv }; } if(ccw < 0){ auto [uw, wu] = newEdge(u, w); insertCcwAfter(uv, uw); insertCcwAfter(vw, vu); insertCcwAfter(wu, wv); return { v, vu }; } return { u, uv }; } int m = (l + r) / 2; auto [a, ea] = solveRange(l, m); auto [b, eb] = solveRange(m, r); return dfs(a, ea, b, eb); } void solve(){ int sz = (int)pos.size(); if(sz <= 1) return; std::vector<int> pi(pos.size()); for(int i=0; i<(int)pi.size(); i++) pi[i] = i; std::sort( pi.begin(), pi.end(), [&](int l, int r){ return pos[l].x != pos[r].x ? pos[l].x < pos[r].x : pos[l].y < pos[r].y; } ); auto posbuf = pos; int posptr = 0; mappings.assign(sz, 0); for(int i=0; i<sz; i++){ int v = pi[i]; if(i == 0 || !(posbuf[pi[posptr-1]] == posbuf[v])){ pi[posptr] = v; pos[posptr++] = posbuf[v]; mappings[v] = v; } else { mappings[v] = pi[posptr-1]; } } if(posptr >= 2) outerOneEdge = solveRange(0, posptr).second; std::swap(pos, posbuf); for(auto& e : edges) e.to = pi[e.to]; } std::vector<int> openAddress; std::vector<GPos2> pos; std::vector<Edge> edges; std::vector<int> mappings; bool voronoiCalculated = false; int outerOneEdge = -1; std::vector<Circumcenter> circumcenters; std::vector<int> voronoiNodeRefLH; CsrArray<std::pair<int,int>> voronoi; void solveVoronoiDiagram(){ if(edges.empty()){ voronoi = CsrArray<std::pair<int,int>>::FromRaw({}, std::vector<int>(pos.size()+1, 0)); voronoiCalculated = true; } if(voronoiCalculated) return; int m = edges.size(); std::vector<int> res(m, -1); int outlineCount = 0; { int eu = outerOneEdge; int es = eu; do{ eu = edges[eu].rev; res[eu] = -2; eu = edges[eu].ccw; outlineCount++; } while(es != eu); } for(int e=0; e<m; e++) if(res[e] == -1){ int f = edges[edges[e].rev].cw; int g = edges[edges[f].rev].cw; int v = edges[e].to; int w = edges[f].to; int u = edges[g].to; int c = circumcenters.size(); circumcenters.push_back(Circumcenter::From3Points(pos[u], pos[v], pos[w])); res[e] = res[f] = res[g] = c; } for(int e=0; e<m; e++) if(res[e] == -2){ int f = edges[e].rev; int v = edges[e].to; int u = edges[f].to; if(res[f] == -2){ int c1 = circumcenters.size(); circumcenters.push_back({ Int2(pos[u].x) + Int2(pos[v].x) + Int2(pos[v].y - pos[u].y), Int2(pos[u].y) + Int2(pos[v].y) - Int2(pos[v].x - pos[u].x), Int2(2) }); int c2 = circumcenters.size(); circumcenters.push_back({ Int2(pos[u].x) + Int2(pos[v].x) - Int2(pos[v].y - pos[u].y), Int2(pos[u].y) + Int2(pos[v].y) + Int2(pos[v].x - pos[u].x), Int2(2) }); res[e] = c1; res[f] = c2; } else { int c1 = circumcenters.size(); auto q = circumcenters[res[f]]; auto d = pos[v] - pos[u]; q.x -= Int3(q.d) * Int3(d.y); q.y += Int3(q.d) * Int3(d.x); circumcenters.push_back(q); res[e] = c1; } } voronoiNodeRefLH = std::move(res); std::vector<int> oneEdge(pos.size(), -1); for(int e=0; e<m; e++) oneEdge[edges[e].to] = edges[e].rev; { std::vector<std::pair<int,int>> res(m*2); std::vector<int> ptr(pos.size() + 1); for(int s=0; s<int(pos.size()); s++){ ptr[s+1] = ptr[s]; if(oneEdge[s] >= 0){ int es = oneEdge[s]; int e = es; do{ int re = edges[e].rev; res[ptr[s+1]++] = { voronoiNodeRefLH[re], voronoiNodeRefLH[e] }; e = edges[e].ccw; } while(e != es); } } voronoi = CsrArray<std::pair<int,int>>::FromRaw(std::move(res), std::move(ptr)); } voronoiCalculated = true; } public: DelaunayTriangulation() : pos() { solve(); } DelaunayTriangulation(std::vector<GPos2> x_points) : pos(std::move(x_points)) { solve(); } std::vector<std::pair<int, int>> getEdges() const { std::vector<std::pair<int, int>> res; for(int e=0; e<(int)edges.size(); e++) if(edges[e].enabled){ int re = edges[e].rev; if(e < re) continue; res.push_back({ edges[e].to, edges[re].to }); } for(int v=0; v<int(mappings.size()); v++){ if(mappings[v] != v) res.push_back({ v, mappings[v] }); } return res; } const std::vector<Circumcenter>& getVirtualCircumcenters(){ solveVoronoiDiagram(); return circumcenters; } std::vector<std::pair<double, double>> getVirtualCircumcentersAsDouble(){ solveVoronoiDiagram(); std::vector<std::pair<double, double>> res(circumcenters.size()); for(int i=0; i<int(circumcenters.size()); i++){ res[i].first = double(circumcenters[i].x) / double(circumcenters[i].d); res[i].second = double(circumcenters[i].y) / double(circumcenters[i].d); } return res; } const CsrArray<std::pair<int,int>>& getVoronoiDiagram(){ solveVoronoiDiagram(); return voronoi; } }; } // namespace nachia namespace nachia { struct DsuFast{ private: std::vector<int> w; public: DsuFast(int n = 0) : w(n, -1) {} int leader(int u){ if(w[u] < 0) return u; return w[u] = leader(w[u]); } int operator[](int u){ return leader(u); } int merge(int u, int v){ u = leader(u); v = leader(v); if(u == v) return u; if(-w[u] < -w[v]) std::swap(u, v); w[u] += w[v]; w[v] = u; return u; } int size(int u){ return -w[leader(u)]; } bool same(int u, int v){ return leader(u) == leader(v); } }; } // namespace nachia void solve(){ int n,m; cin >> n; using i64 = long long; using Point = nachia::VecI2<i64, i64>; vector<i64> xa(n),ya(n); rep(i,n) cin >> xa[i] >> ya[i]; cin >> m; vector<i64> xb(m),yb(m); rep(i,m) cin >> xb[i] >> yb[i]; vector<i64> x(n+m),y(n+m); rep(i,n){ x[i] = xa[i]; y[i] = ya[i]; } rep(i,m){ x[i+n] = xb[i]; y[i+n] = yb[i]; } std::vector<Point> A(n+m); rep(i,n+m){ A[i].x = x[i]; A[i].y = y[i]; } auto weight = [&](std::pair<int,int> p){ return (abs(A[p.first].x - A[p.second].x)+abs(A[p.first].y - A[p.second].y)); }; auto tri = nachia::DelaunayTriangulation(A).getEdges(); std::sort(tri.begin(), tri.end(), [&](std::pair<int,int> l, std::pair<int,int> r) -> bool { return weight(l) < weight(r); }); auto dsu = nachia::DsuFast(n+m); std::vector<std::pair<int,int>> ans; for(auto a : tri){ if(dsu.same(a.first, a.second)) continue; dsu.merge(a.first, a.second); if(a.first > a.second) std::swap(a.first, a.second); ans.push_back(a); } std::sort(ans.begin(), ans.end()); ll anser = 1e9; for(auto a : ans)if((a.first > n && a.second <= n) || (a.first <= n && a.second > n)){ ll now = abs(A[a.first].x - A[a.second].x)+abs(A[a.first].y - A[a.second].y); chmin(anser,now); } cout << anser << endl; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int t = 1; //cin >> t; rep(testcase,t) solve(); }