BZOJ4152 坠短路优化建边 我的第一次超级大封装

大家都很强, 可与之共勉 。

题意:
  您有 n(n2e5) 个点,以一个 pair(x,y) 给出,表示横纵坐标 (0x,y1e9) 。求从 1 号点到n号点的坠短路。两点之间的距离定义为 min(|x1x2|,|y1y2|)

题解:
  其实很早之前就做了这道题,大约是在 7 月的ACM里面做的。前几天 YJQOrzOrzOrz 又在图论讲课中提到了这道题。
  于是重新来写一下,顺便(滑稽)搞一波完全大封装。

  考虑朴素的连边方案。有 O(n2) 条边,好刺激吖。但是我们发现这里面的很多边其实是有个卵用的。举个栗子:
   1>2,2>3,1>3 1,2,3 之间的距离都是由 x y计算出来的时候那么 1>3 就是没用的,我萌可以直接扔掉她( 1>2>3 的长度等价于 1>3 )。
  所以我们分类讨论,考虑是按什么为关键字计算距离,于是关于 x y为关键字分别从小到大排序。
  然后点 a 向后继连边,代价为当前关键字之差绝对值。

  这样是O(n)的边数,我萌可以接受。
  然后直接上 Dijkstra 就好啦。

  封装真好玩,可是好慢啊

/**************************************************************
    Problem: 4152
    User: Lazer2001
    Language: C++
    Result: Accepted
    Time:4012 ms
    Memory:36064 kb
****************************************************************/

# include <bits/stdc++.h>

namespace In  {
# define In_Len 6000000
    static std :: streambuf *fb ( std :: cin.rdbuf ( ) ) ;
    static char buf [In_Len], *ss ( 0 ) ;

    void init ( )  {  fb -> sgetn ( ss = buf, In_Len ) ;  }

    inline int read ( )  {
        register int x ;
        bool opt ( 1 ) ;
        while ( isspace ( *ss ) )  ++ ss ;
        if ( *ss == 45 )  { ++ ss ; opt = 0 ; }
        for ( x = -48 + *ss ; isdigit ( * ++ ss ) ; ( x *= 10 ) += *ss - 48 ) ; ++ ss ;
        return opt ? x : -x ;
    }
# undef pick
# undef In_Len
}

template < class T >  inline bool chkmin ( T& d, const T& x )  {  return ( d > x ) ? ( d = x ), 1 : 0 ;    }

template < class T, int N >
class Heap  {
    private :
        int len ;
        T a [N] ;
    public :
        Heap ( )  {  len = 0 ;  }
        inline void push ( const T& ele )  {
            a [++ len] = ele ;
            std :: push_heap ( a + 1, a + 1 + len, std :: greater < T > ( ) ) ;
        }
        inline void pop ( )  {
            std :: pop_heap ( a + 1, a + 1 + len --, std :: greater < T > ( ) ) ;
        }
        inline bool empty ( )  {
            return len == 0 ;
        }
        inline T top ( )  {
            return a [1] ;
        }
} ;

template < int N >
class Dijkstra  {
    private :
        struct edge  {
            int to, w ; edge* nxt ;
        } g [N << 2], *head [N], *cur ;
        int dis [N] ;
        Heap < std :: pair < int, int >, N * 10 > Q ;
    public :
        Dijkstra ( )  {  cur = g ;  }
        inline void add_edge ( int u, int v, int w, bool db = 1 )  {
            *cur = ( edge )  {  v, w, head [u]  } ; head [u] = cur ++ ;
            if ( db )  add_edge ( v, u, w, 0 ) ;
        }
        inline int dijkstra ( int S, int T )  {
            memset ( dis, 0x3f, sizeof dis ) ;
            Q.push ( std :: make_pair ( dis [S] = 0, S ) ) ;
            while ( ! Q.empty ( ) )  {
                int u = Q.top ( ).second ; Q.pop ( ) ;
                for ( edge* it = head [u] ; it ; it = it -> nxt )
                    if ( chkmin ( dis [it -> to], dis [u] + it -> w ) )  {
                        Q.push ( std :: make_pair ( dis [it -> to], it -> to ) ) ;
                    }
            }
            return dis [T] ;
        }
} ;

Dijkstra < 200010 > Gp ;

template < class T1, class T2 >
struct cmp_x  {
    inline bool operator ( ) ( const std :: pair < T1, T2 >& a, const std :: pair < T1, T2 >& b )  {
        return a.first < b.first ;
    }
} ;

template < class T1, class T2 >
struct cmp_y  {
    inline bool operator ( ) ( const std :: pair < T1, T2 >& a, const std :: pair < T1, T2 >& b )  {
        return a.second < b.second ;
    }
} ;

std :: pair < int, std :: pair < int, int > > p [200010] ;

int main ( )  {

    In :: init ( ) ;

    int n ;

    n = In :: read ( ) ;

    for ( int i = 1 ; i <= n ; ++ i )  {
        static int x, y ;
        x = In :: read ( ), y = In :: read ( ) ;
        p [i] = std :: make_pair ( x, std :: make_pair ( y, i ) ) ;
    }

    std :: sort ( p + 1, p + 1 + n, cmp_x < int, std :: pair < int, int > > ( ) ) ;

    for ( int i = 1 ; i < n ; ++ i )  {
        Gp.add_edge ( p [i].second.second, p [i + 1].second.second, p [i + 1].first - p [i].first ) ;
    }

    std :: sort ( p + 1, p + 1 + n, cmp_y < int, std :: pair < int, int > > ( ) ) ;

    for ( int i = 1 ; i < n ; ++ i )  {
        Gp.add_edge ( p [i].second.second, p [i + 1].second.second, p [i + 1].second.first - p [i].second.first ) ;
    }

    printf ( "%d\n", Gp.dijkstra ( 1, n ) ) ;

    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值