ZROI#962

ZROI#962

看起来很数据结构的一道题,其实就是很数据结构...
\(\Theta(nmq)\)的暴力很无脑,是个人应该都会.
\(Code:\)

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
#define MEM(x,y) memset ( x , y , sizeof ( x ) )
#define rep(i,a,b) for (int i = (a) ; i <= (b) ; ++ i)
#define per(i,a,b) for (int i = (a) ; i >= (b) ; -- i)
#define pii pair < int , int >
#define X first
#define Y second
#define rint read<int>
#define int long long
#define pb push_back

using std::queue ;
using std::set ;
using std::pair ;
using std::max ;
using std::min ;
using std::priority_queue ;
using std::vector ;
using std::swap ;
using std::sort ;
using std::unique ;
using std::greater ;

template < class T >
    inline T read () {
        T x = 0 , f = 1 ; char ch = getchar () ;
        while ( ch < '0' || ch > '9' ) {
            if ( ch == '-' ) f = - 1 ;
            ch = getchar () ;
        }
       while ( ch >= '0' && ch <= '9' ) {
            x = ( x << 3 ) + ( x << 1 ) + ( ch - 48 ) ;
            ch = getchar () ;
       }
   return f * x ;
}

const int N = 3e3 + 100 ;

int n , m , Q , e[N][N] , dis[N][N] ;
bool vis[N][N] ;
int fx[] = { 1 , 0 , - 1 , 0 } ;
int fy[] = { 0 , 1 , 0 , - 1 } ;

queue < pii > q ;
inline int bfs (int sx , int sy , int tx , int ty , int val) {
    if ( sx == tx && sy == ty ) return 0 ;
    if ( e[sx][sy] > val || e[tx][ty] > val ) return - 1 ;
    while ( ! q.empty () ) q.pop () ;
    rep ( i , 1 , n ) rep ( j , 1 , m ) vis[i][j] = dis[i][j] = 0 ;
    dis[sx][sy] = 0 ; q.push ( { sx , sy } ) ; vis[sx][sy] = true ;
    while ( ! q.empty () ) {
        pii cur = q.front () ; q.pop () ;
        for (int i = 0 ; i < 4 ; ++ i) {
            int dx = cur.X + fx[i] , dy = cur.Y + fy[i] ;
            if ( vis[dx][dy] || e[dx][dy] > val || dx < 1 || dy < 1 || dx > n || dy > m ) continue ;
            vis[dx][dy] = true ; dis[dx][dy] = dis[cur.X][cur.Y] + 1 ; q.push ( { dx , dy } ) ;
            if ( dx == tx && dy == ty ) return dis[dx][dy] ;
        }
    }
    return - 1 ;
}

inline void update (int type , int pos) {
    if ( type == 1 ) for (int i = 1 ; i <= m ; ++ i) e[pos][i] = 0 ;
    else for (int i = 1 ; i <= n ; ++ i) e[i][pos] = 0 ;
    return ;
}

inline void grow () { rep ( i , 1 , n ) rep ( j , 1 , m ) ++ e[i][j] ; return ; }

signed main (int argc , char * argv[]) {
    n = rint () ; m = rint () ; Q = rint () ;
    while ( Q -- ) {
        grow () ; int k = rint () ;
        if ( k != 3 ) {
            int pos = rint () ;
            update ( k , pos ) ;
        }
        else {
            int sx = rint () , sy = rint () ;
            int tx = rint () , ty = rint () , val = rint () ;
            printf ("%lld\n" , bfs ( sx , sy , tx , ty , val ) ) ;
        }
    }
    return 0 ;
}

然后考虑\(\Theta(n^2)\)怎么做,我们可以对每次操作前的整个矩阵加\(1\)操作维护一个全局标记实现.
我们再对行和列分别维护一个数组记录它最近一次被修改的时间\(t\).
若当前时间为\(cur\),询问限制权值为\(val\),则如果一个点存在横坐标纵坐标的\(t\)中至少一个满足\(t-cur\le val\)就是可行点.
我们只需要考虑有多少种连通情况即可.
共八种:
L型:
1.一个点的行和另一个点的列都可行
2.同上,两个点的对应行列都要判
Z型:
3.两个点所在行可行,只需要中间有一列可行即可.
4.两个点所在列可行,只需要中间有一行可行即可.
瞎走型:
5.两点之间所有的行都是可行的
6.两点之间所有的列都是可行的
外绕型:
7.两个点所在行可行,但中间没有可行列,需要到两点纵坐标之外寻找是否存在可行列
8.两个点所在列可行,但中间没有可行行,需要到两点横坐标之外寻找是否存在可行行.
显然,如果两个点连通,那么一定是上面八种情况之一.
于是\(\Theta(n^2)\)就就解决了.
\(\Theta(n^2)\)的暴力没写,我直接写了正解.
我们再来考虑怎么写没有\(2\)操作的部分分.
容易发现,如果不存在\(2\)操作,那么就只需要考虑两个点之间的行是否可行就行了,直接对行建线段树即可.
好了,终于到了正解了!
其实上面的部分分都会了的话,正解就一目了然了.
对行和列分别建一棵线段树,直接维护即可.
但你会发现\(7,8\)两种操作你不能直接线段树解决,因为你还要最小化距离.
所以我们考虑二分+线段树或线段树上二分.二者的区别在于实现和复杂度一个为\(\Theta(log_2^2n)\)而另一个为\(\Theta(log_2n)\).
显然,二分+线段树是两个\(log\)的,而线段树上二分是一个\(log\)的.我写的是两个\(log\)的,反正能过,谁管是啥呢.
因为你需要一段连续能走的,所以你要固定一个端点不动,你二分的是另一个端点的位置.
以点\((a,b)\)为例,如果你要往左找,那你应该查询的区间是\([mid,a-1]\),而向左向右缩短/扩张区间需要移动的端点是不一样的,要注意.
\(Code:\)

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
#define MEM(x,y) memset ( x , y , sizeof ( x ) )
#define rep(i,a,b) for (int i = (a) ; i <= (b) ; ++ i)
#define per(i,a,b) for (int i = (a) ; i >= (b) ; -- i)
#define pii pair < int , int >
#define one first
#define two second
#define rint read<int>
#define int long long
#define pb push_back

using std::queue ;
using std::set ;
using std::pair ;
using std::max ;
using std::min ;
using std::priority_queue ;
using std::vector ;
using std::swap ;
using std::sort ;
using std::unique ;
using std::greater ;

template < class T >
    inline T read () {
        T x = 0 , f = 1 ; char ch = getchar () ;
        while ( ch < '0' || ch > '9' ) {
            if ( ch == '-' ) f = - 1 ;
            ch = getchar () ;
        }
       while ( ch >= '0' && ch <= '9' ) {
            x = ( x << 3 ) + ( x << 1 ) + ( ch - 48 ) ;
            ch = getchar () ;
       }
   return f * x ;
}

const int inf = 0x7f7f7f7f ;

class segment {
    #define ls ( rt << 1 )
    #define rs ( rt << 1 | 1 )
    #define mid ( ( l + r ) >> 1 )
    private :
        static const int M = 1e5 + 100 ;
    private :
        struct seg { int left , right , maxn , minn ; } t[(M<<2)] ;
    private :
        inline void pushup (int rt) {
            t[rt].maxn = max ( t[ls].maxn , t[rs].maxn ) ;
            t[rt].minn = min ( t[ls].minn , t[rs].minn ) ;
            return ;
        }
    public :
        inline void build (int rt , int l , int r) {
            t[rt].left = l ; t[rt].right = r ;
            if ( l == r ) { t[rt].maxn = t[rt].minn = 0 ; return ; }
            build ( ls , l , mid ) ; build ( rs , mid + 1 , r ) ;
            pushup ( rt ) ; return ;
        }
    public :
        inline void coverp (int rt , int pos , int val) {
            int l = t[rt].left , r = t[rt].right ;
            if ( l == pos && pos == r ) { t[rt].minn = t[rt].maxn = val ; return ; }
            if ( pos <= mid ) coverp ( ls , pos , val ) ;
            else coverp ( rs , pos , val ) ;
            pushup ( rt ) ; return ;
        }
    public :
        inline int qmax (int rt , int ll , int rr) {
            int l = t[rt].left , r = t[rt].right ;
            if ( l == ll && r == rr ) return t[rt].maxn ;
            if ( rr <= mid ) return qmax ( ls , ll , rr ) ;
            else if ( ll > mid ) return qmax ( rs , ll , rr ) ;
            else return max ( qmax ( ls , ll , mid ) , qmax ( rs , mid + 1 , rr ) ) ;
        }
    public :
        inline int qmin (int rt , int ll , int rr) {
            int l = t[rt].left , r = t[rt].right ;
            if ( l == ll && r == rr ) return t[rt].minn ;
            if ( rr <= mid ) return qmin ( ls , ll , rr ) ;
            else if ( ll > mid ) return qmin ( rs , ll , rr ) ;
            else return min ( qmin ( ls , ll , mid ) , qmin ( rs , mid + 1 , rr ) ) ;
        }
    #undef ls
    #undef rs
    #undef mid
} line , row ;

int n , m , Q , cur ;

inline int mabs (int x) { return x < 0 ? - x : x ; }

inline int Manhattan (int sx , int sy , int tx , int ty) { return mabs ( sx - tx ) + mabs ( sy - ty ) ; }

inline int deal (int a , int b , int c , int d , int val) {
    // 行全行
    int lines = line.qmin ( 1 , min ( a , c ) , max ( a , c ) ) ;
    if ( cur - lines <= val ) return Manhattan ( a , b , c , d ) ;

    // 列全行
    int rows = row.qmin ( 1 , min ( b , d ) , max ( b , d ) ) ;
    if ( cur - rows <= val ) return Manhattan ( a , b , c , d ) ;

    // L 型-下左
    int Arow = row.qmax ( 1 , b , b ) , Bline = line.qmax ( 1 , c , c ) ;
    if ( cur - Arow <= val && cur - Bline <= val ) return Manhattan ( a , b , c , d ) ;

    // L 型-上右
    int Aline = line.qmax ( 1 , a , a ) , Brow = row.qmax ( 1 , d , d ) ;
    if ( cur - Brow <= val && cur - Aline <= val ) return Manhattan ( a , b , c , d ) ;

    // 内 Z 型-两行一列 
    rows = row.qmax ( 1 , min ( b , d ) , max ( b , d ) ) ;
    if ( cur - Aline <= val && cur - Bline <= val && cur - rows <= val ) return Manhattan ( a , b , c , d ) ;

    // 内 Z 型-两列一行
    lines = line.qmax ( 1 , min ( a , c ) , max ( a , c ) ) ;
    if ( cur - Arow <= val && cur - Brow <= val && cur - lines <= val ) return Manhattan ( a , b , c , d ) ;

    // 外 Z 型-两行+外绕
    if ( cur - Aline <= val && cur - Bline <= val && cur - rows > val ) {
        int res = inf ;
        if ( b > d ) swap ( b , d ) ;
        int l = 1 , r = b - 1 , pos = - 1 ;
        while ( l <= r ) {
            int mid = ( l + r ) >> 1 ;
            if ( cur - row.qmax ( 1 , mid , b - 1 ) <= val ) { pos = mid ; l = mid + 1 ; }
            else r = mid - 1 ;
        }
        if ( pos != - 1 ) res = min ( res , mabs ( pos - b ) * 2 ) ;
        l = d + 1 ; r = m ;
        while ( l <= r ) {
            int mid = ( l + r ) >> 1 ;
            if ( cur - row.qmax ( 1 , d + 1 , mid ) <= val ) { pos = mid ; r = mid - 1 ; }
            else l = mid + 1 ;
        }
        if ( pos != - 1 ) res = min ( res , mabs ( pos - d ) * 2 ) ;
        if ( pos != - 1 ) return Manhattan ( a , b , c , d ) + res ;
    }

    // 外 Z 型-两列+外绕
    if ( cur - Arow <= val && cur - Brow <= val && cur - lines > val ) {
        int res = inf ;
        if ( a > c ) swap ( a , c ) ;
        int l = 1 , r = a - 1 , pos = - 1 ;
        while ( l <= r ) {
            int mid = ( l + r ) >> 1 ;
            if ( cur - line.qmax ( 1 , mid , a - 1 ) <= val ) { pos = mid ; l = mid + 1 ; }
            else r = mid - 1 ;
        }
        if ( pos != - 1 ) res = min ( res , mabs ( pos - a ) * 2 ) ;
        l = c + 1 ; r = n ;
        while ( l <= r ) {
            int mid = ( l + r ) >> 1 ;
            if ( cur - line.qmax ( 1 , c + 1 , mid ) <= val ) { pos = mid ; r = mid - 1 ; }
            else l = mid + 1 ;
        }
        if ( pos != - 1 ) res = min ( res , mabs ( pos - c ) * 2 ) ;
        if ( pos != - 1 ) return Manhattan ( a , b , c , d ) + res ;
    }

    // 不连通
    return - 1 ;
}

signed main (int argc , char * argv[]) {
    n = rint () ; m = rint () ; Q = rint () ;
    line.build ( 1 , 1 , n ) ; row.build ( 1 , 1 , m ) ;
    while ( Q -- ) {
        int k = rint () ; ++ cur ;
        if ( k != 3 ) {
            int pos = rint () ;
            if ( k == 1 ) line.coverp ( 1 , pos , cur ) ;
            if ( k == 2 ) row.coverp ( 1 , pos , cur ) ;
        } else {
            int sx = rint () , sy = rint () ;
            int tx = rint () , ty = rint () , val = rint () ;
            if ( sx == tx && sy == ty ) { puts ("0") ; continue ; }
            printf ("%lld\n" , deal ( sx , sy , tx , ty , val ) ) ;
        }
    }
    return 0 ;
}
posted @ 2019-09-17 19:08  Phecda  阅读(190)  评论(0编辑  收藏  举报

Contact with me