Live2D

Solution -「JOISC 2021」「LOJ #3491」道路建设

\(\mathcal{Description}\)

  Link.

  平面上有 \(n\) 个互不重合的点 \((x_{1..n},y_{1..n})\),求其两两曼哈顿距离的前 \(m\) 小值。

  \(n,m\le2.5\times10^5\)

\(\mathcal{Solution}\)

  会做,但不完全会做。

  数前 \(k\) 小的一种技术是:将解大致分类,在每类中维护最优解,一起放入堆中迭代。

  应用到本题,按 \((x,y)\) 的二维偏序排序后,对于每个点,尝试维护其前方的所有点与它构成的答案信息。具体地,对于当前 \((x,y)\),维护了 \((x',y')\) 与它的曼哈顿距离,必然有 \(x'\le x\),所以仅需考虑 \(y\)\(y'\) 的关系,分别取正负号,用可持久化线段树维护一发即可。

  复杂度 \(\mathcal O((n+m)\log n)\),空间同阶。

\(\mathcal{Code}\)

/* Clearink */

#include <queue>
#include <cstdio>
#include <vector>
#include <cassert>
#include <iostream>
#include <algorithm>

#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )

typedef long long LL;
#define int LL
typedef std::pair<int, int> PII;
typedef std::pair<LL, int> PLI;
#define fi first
#define se second

inline int rint() {
    int x = 0, f = 1, s = getchar();
    for ( ; s < '0' || '9' < s; s = getchar() ) f = s == '-' ? -f : f;
    for ( ; '0' <= s && s <= '9'; s = getchar() ) x = x * 10 + ( s ^ '0' );
    return x * f;
}

template<typename Tp>
inline void wint( Tp x ) {
    if ( x < 0 ) putchar( '-' ), x = -x;
    if ( 9 < x ) wint( x / 10 );
    putchar( x % 10 ^ '0' );
}

inline int iabs( const int a ) { return a < 0 ? -a : a; }

const int MAXN = 2.5e5;
const LL IINF = 1ll << 60;
int n, m, mx, dy[MAXN + 5], root[MAXN + 5];
PII pt[MAXN + 5];
std::vector<int> ybuc[MAXN + 5];
std::priority_queue<PLI, std::vector<PLI>, std::greater<PLI> > heap;

struct SegmentTree {
    static const int MAXND = 1e7;
    int node, ch[MAXND][2];
    PII amn[MAXND], smn[MAXND];

    SegmentTree() { amn[0] = smn[0] = { IINF, 0 }; }

    inline void copy( const int u, const int v ) {
        ch[u][0] = ch[v][0], ch[u][1] = ch[v][1],
        amn[u] = amn[v], smn[u] = smn[v];
    }

    inline void pushup( const int u ) {
        amn[u] = std::min( amn[ch[u][0]], amn[ch[u][1]] );
        smn[u] = std::min( smn[ch[u][0]], smn[ch[u][1]] );
    }

    inline void modify( int& u, const int l, const int r,
      const int x, const int y ) {
        int v = u, mid = l + r >> 1; copy( u = ++node, v );
        if ( l == r ) {
            if ( x == IINF ) u = 0;
            else amn[u] = { -x + dy[y], l }, smn[u] = { -x - dy[y], l };
            return ;
        }
        if ( y <= mid ) modify( ch[u][0], l, mid, x, y );
        else modify( ch[u][1], mid + 1, r, x, y );
        pushup( u );
    }

    inline PII query( const int u, const int l, const int r,
      const int ql, const int qr, const bool type ) const {
        if ( !u ) return { IINF, 0 };
        if ( ql <= l && r <= qr ) return type ? amn[u] : smn[u];
        int mid = l + r >> 1; PII ret( IINF, 0 );
        if ( ql <= mid ) {
            ret = std::min( ret, query( ch[u][0], l, mid, ql, qr, type ) );
        }
        if ( mid < qr ) {
            ret = std::min( ret, query( ch[u][1], mid + 1, r, ql, qr, type ) );
        }
        return ret;
    }

    inline PLI calc( const int rt, const int x, const int y ) {
        PII up( query( rt, 1, mx, y, mx, true ) ),
          dn( query( rt, 1, mx, 1, y, false ) );
        LL u = 0ll + x - dy[y] + up.fi, d = 0ll + x + dy[y] + dn.fi;
        if ( u <= d ) return PLI( u, up.se );
        else return PLI( d, dn.se );
    }
} sgt;

signed main() {
    n = rint(), m = rint();
    rep ( i, 1, n ) pt[i].fi = rint(), dy[i] = pt[i].se = rint();
    
    std::sort( pt + 1, pt + n + 1 );
    std::sort( dy + 1, dy + n + 1 );
    mx = std::unique( dy + 1, dy + n + 1 ) - dy - 1;
    rep ( i, 1, n ) {
        pt[i].se = std::lower_bound( dy + 1, dy + mx + 1, pt[i].se ) - dy;
        ybuc[pt[i].se].push_back( pt[i].fi );
    }

    rep ( i, 1, mx ) std::sort( ybuc[i].begin(), ybuc[i].end() );

    rep ( i, 2, n ) {
        root[i] = root[i - 1];
        sgt.modify( root[i], 1, mx, pt[i - 1].fi, pt[i - 1].se );
        heap.push( { sgt.calc( root[i], pt[i].fi, pt[i].se ).fi, i } );
    }

    while ( m-- ) {
        PLI p( heap.top() ); heap.pop();
        wint( p.fi ), putchar( '\n' );

        int yv( sgt.calc( root[p.se], pt[p.se].fi, pt[p.se].se ).se );
        int x = 0ll + iabs( dy[pt[p.se].se] - dy[yv] ) + pt[p.se].fi - p.fi;
        int id = std::lower_bound( ybuc[yv].begin(), ybuc[yv].end(), x )
          - ybuc[yv].begin(), nx = id ? ybuc[yv][id - 1] : IINF;

        sgt.modify( root[p.se], 1, mx, nx, yv );
        heap.push( { sgt.calc( root[p.se], pt[p.se].fi, pt[p.se].se ).fi,
          p.se } );
    }
    return 0;
}

posted @ 2021-06-21 18:56  Rainybunny  阅读(78)  评论(0编辑  收藏  举报