zoukankan      html  css  js  c++  java
  • 「JOISC 2019 Day3」穿越时空 Bitaro

    题目

    点这里看题目。

    分析

    一些简单的转化:

    • 其一,将原先的区间 ([L,R]) 都变成 ([L,R-1])
    • 其二,将 ([L_i,R_i]) 变成 ([L_i-i,R_i-i]) ,这样就不需要考虑时间的自然流逝了。

    考虑一个简单的贪心:维护当前的时间 (t) 。如果下一段路的区间为 ([L,R]) ,那么若 (t>R) ,我们就必须使用技能移到 (R) 然后通过;若 (t<L) ,我们就必须等到 (L) 然后通过;否则可以直接通过。

    继续考虑多个区间叠加的情况。可以发现只会有两种可能:

    1. 存在一段区间 ([l, r]) ,满足当 (tin [l,r]) 时可以直接穿过这段区间。

    2. 不存在这样的 ([l,r]) ,那么我们总可以认为穿过这段区间的效果是:初始时刻 (a) ,到达时刻 (b) ,必须使用 (k) 次技能。

      这是因为我们可以在过区间的时候,将穿过后的一些技能平移到穿过前,这样我们的初始时刻就是相同的;同样也可以将穿过前的平移到穿过后,这样到达时刻就是相同的。

    注意到两种情况时可以合并的,只是有亿点点复杂,所以我们就可以使用线段树维护一段区间的情况。

    小结:

    1. 将情况分类讨论的灵活处理比较有价值,有的时候没有必要(也不能)强行归为一类。

    代码

    #include <cstdio>
    
    #define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
    #define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
    
    typedef long long LL;
    
    const int MAXN = 3e5 + 5;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0;char s = getchar();int f = 1;
    	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
    	while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
    	x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
    	if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
    	if( 9 < x ){ write( x / 10 ); }
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    _T MAX( const _T a, const _T b )
    {
    	return a > b ? a : b;
    }
    
    template<typename _T>
    _T MIN( const _T a, const _T b )
    {
    	return a < b ? a : b;
    }
    
    struct Period
    {
    	int a, b; LL t; bool c;
    	Period() { a = - 1e9, b = 1e9, c = t = 0; }
    	Period( const int L, const int R ) { a = L, b = R, c = t = 0; }
    	Period( int A, int B, bool C, LL T ) { a = A, b = B, c = C, t = T; }
    
    	LL operator () ( const LL sta ) const 
    	{
    		if( c ) return t + ( sta > a ? sta - a : 0 );
    		return t + ( sta > b ? sta - b : 0 );
    	}
    };
    
    Period operator + ( const Period &x, const Period &y )
    {
    	Period ret;
    	if( ! x.c && ! y.c )
    	{
    		if( MAX( x.a, y.a ) <= MIN( x.b, y.b ) )
    			ret = Period( MAX( x.a, y.a ), MIN( x.b, y.b ), 0, x.t + y.t );
    		else
    		{
    			if( y.b < x.a ) ret = Period( x.a, y.b, 1, x.t + y.t + x.a - y.b );
    			else ret = Period( x.b, y.a, 1, x.t + y.t );
    		}
    	}
    	else if( ! x.c )
    	{
    		if( x.b < y.a ) ret = Period( x.b, y.b, 1, x.t + y.t );
    		else if( y.a < x.a ) ret = Period( x.a, y.b, 1, x.t + y.t + x.a - y.a );
    		else ret = y;
    	}
    	else if( ! y.c )
    	{
    		if( y.b < x.b ) ret = Period( x.a, y.b, 1, x.t + y.t + x.b - y.b );
    		else if( x.b < y.a ) ret = Period( x.a, y.a, 1, x.t + y.t );
    		else ret = x;
    	}
    	else ret = Period( x.a, y.b, 1, x.t + y.t + ( x.b > y.a ? x.b - y.a : 0 ) );
    	return ret;
    }
    
    struct Tree
    {
    	Period per[MAXN << 2];
    	
    	void Upt( const int x ) { per[x] = per[x << 1] + per[x << 1 | 1]; }
    	
    	void Update( const int x, const int l, const int r, const int p, const Period nw )
    	{
    		if( l == r ) return void( per[x] = nw );
    		int mid = l + r >> 1;
    		if( p <= mid ) Update( x << 1, l, mid, p, nw );
    		else Update( x << 1 | 1, mid + 1, r, p, nw );
    		Upt( x );
    	}
    	
    	Period Query( const int x, const int l, const int r, const int segL, const int segR )
    	{
    		if( segL > segR ) return Period();
    		if( segL <= l && r <= segR ) return per[x];
    		int mid = l + r >> 1; Period ret;
    		if( segL <= mid ) ret = ret + Query( x << 1, l, mid, segL, segR );
    		if( mid < segR ) ret = ret + Query( x << 1 | 1, mid + 1, r, segL, segR );
    		return ret;
    	}
    }nor, rev;
    
    int L[MAXN], R[MAXN];
    int N, Q;
    
    int main()
    {
    	read( N ), read( Q );
    	rep( i, 1, N - 1 )
    	{
    		read( L[i] ), read( R[i] ), R[i] --;
    		nor.Update( 1, 1, N - 1, i, Period( L[i] - i, R[i] - i ) );
    		rev.Update( 1, 1, N - 1, N - i, Period( L[i] - N + i, R[i] - N + i ) );
    	}
    	int opt, A, B, C, D;
    	while( Q -- )
    	{
    		read( opt );
    		if( opt == 1 )
    		{
    			read( A ), read( B ), read( C ), C --;
    			nor.Update( 1, 1, N - 1, A, Period( B - A, C - A ) );
    			rev.Update( 1, 1, N - 1, N - A, Period( B - N + A, C - N + A ) );
    		}
    		else
    		{
    			Period res; LL ans = 0;
    			read( A ), read( B ), read( C ), read( D );
    			if( A < C ) 
    				res = nor.Query( 1, 1, N - 1, A, C - 1 ), B -= A, D -= C;
    			else 
    				res = rev.Query( 1, 1, N - 1, N - A + 1, N - C ), B -= N - A + 1, D -= N - C + 1;
    
    			if( res.c )
    			{
    				ans = res.t;
    				if( B > res.a ) ans += B - res.a;
    				B = res.b;
    				if( B > D ) ans += B - D;
    			}
    			else
    			{
    				ans = res.t;
    				if( B < res.a ) B = res.a;
    				else if( B > res.b ) ans = B - res.b, B = res.b;
    				if( B > D ) ans += B - D;
    			}
    			write( ans ), putchar( '
    ' );
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    配置Harbor支持https功能实战篇
    Docker自建仓库之Harbor部署实战
    Docker自建仓库之Harbor高可用部署实战篇
    Docker自建仓库之Docker Registry部署实战
    Docker Hub镜像公共仓库使用
    阿里云镜像公共仓库使用
    自定义haproxy镜像
    HAProxy常见的安装方式
    自定义tomcat业务镜像
    自定义Tomcat的基础镜像
  • 原文地址:https://www.cnblogs.com/crashed/p/14413210.html
Copyright © 2011-2022 走看看