• [NOI2020省选]冰火战士


    题目

    点这里看题目。

    分析

    (F(T))为温度为(T)的时候火系战士能量和,(I(T))(T)时冰系战士能量和。

    显然我们需要求:

    [max{min{F(T),I(T)}} ]

    另一个显然的事情是,(F(T))是一个后缀和,(I(T))是一个前缀和;因而(F(T))单减,(I(T))单增。

    那么(min{F(T),I(T)})就应该是一个有最高平台的函数。

    更进一步的,设(T_1=max{T|I(T)le F(T)},T_2=min{T|F(T)<I(T)}),那么我们可以知道,峰要么是(I(T_1)),要么是(F(T_2))

    首先我们可以离散化后,用树状数组维护一下(I)的前缀和和(F)前缀差和。计算(F)的时候,我们用能量和减掉范围外的。

    寻找(T_1),我们可以直接在树状数组上面二分。具体来说,我们实际上枚举步长来进行倍增,并利用树状数组得到当前的前缀信息。

    寻找(F(T_2)),我们可以直接找出(T_1)的后继(T_2'),那么(F(T_2)=F(T_2'))。不过,有可能(T_2'<T_2),我们需要在树状数组上面把(F(T_2'))的值代入,二分找出(T_2)

    所以总共应该有两个二分,一个寻找(T_1),一个寻找(T_2)

    时间复杂度是(O(nlog_2n)),非常非常卡,需要卡常或者 O2 。

    代码

    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    
    const int MAXN = 2e6 + 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' );
    }
    
    struct oper
    {
    	int type, id, x, y;
    }op[MAXN];
    
    int F[MAXN], I[MAXN];
    int temp[MAXN];
    int typ[MAXN], T[MAXN], E[MAXN];
    int Q, N, lg2, all;
    
    void up( int &x ) { x += x & ( -x ); }
    void down( int &x ) { x &= ( x - 1 ); }
    void uptF( int x, const int v ) { for( ; x <= N ; up( x ) ) F[x] += v; }
    void uptI( int x, const int v ) { for( ; x <= N ; up( x ) ) I[x] += v; }
    int getF( int x ) { int ret = 0; for( ; x ; down( x ) ) ret += F[x]; return ret; }
    int getI( int x ) { int ret = 0; for( ; x ; down( x ) ) ret += I[x]; return ret; }
    
    int find1()
    {
    	int p = 0, ice = 0, fire = 0, tmp;
    	for( int s = 1 << lg2 ; s ; s >>= 1 )
    	{
    		tmp = p + s;
    		if( tmp > N ) continue;
    		ice += I[tmp];
    		fire += F[tmp];
    		if( ice <= all - fire ) p = tmp;
    		else ice -= I[tmp], fire -= F[tmp];
    	}
    	return p;
    }
    
    int find2( const int tar )
    {
    	int p = 0, fire = 0, tmp;
    	for( int s = 1 << lg2 ; s ; s >>= 1 )
    	{
    		tmp = p + s;
    		if( tmp > N ) continue;
    		fire += F[tmp];
    		if( all - fire >= tar ) p = tmp;
    		else fire -= F[tmp];
    	}
    	return p;
    }
    
    int main()
    {
    	read( Q );
    	for( int i = 1 ; i <= Q ; i ++ )
    	{
    		read( op[i].type ), read( op[i].id );
    		if( op[i].type == 1 ) 
    			read( op[i].x ), read( op[i].y ), temp[++ N] = op[i].x;
    	}
    	std :: sort( temp + 1, temp + 1 + N );
    	N = std :: unique( temp + 1, temp + 1 + N ) - temp - 1;
    	lg2 = log2( N ); int pos, p1, e1, p2, e2;
    	for( int i = 1 ; i <= Q ; i ++ )
    	{
    		if( op[i].type == 1 )
    		{
    			pos = std :: lower_bound( temp + 1, temp + 1 + N, op[i].x ) - temp;
    			if( op[i].id ) all += op[i].y, uptF( pos + 1, op[i].y );
    			else uptI( pos, op[i].y );
    			typ[i] = op[i].id, T[i] = pos, E[i] = op[i].y;
    		}
    		else
    		{
    			pos = op[i].id;
    			if( typ[pos] ) all -= op[pos].y, uptF( T[pos] + 1, -E[pos] );
    			else uptI( T[pos], - E[pos] );
    		}
    		p1 = find1(), e1 = getI( p1 );
    		p2 = p1 == N ? N : p1 + 1, e2 = all - getF( p2 );
    		if( e1 == 0 && e2 == 0 ) { puts( "Peace" ); continue; }
    		if( e1 > e2 ) write( temp[p1] ), putchar( ' ' ), write( e1 * 2ll ), putchar( '
    ' );
    		else write( temp[find2( e2 )] ), putchar( ' ' ), write( e2 * 2ll ), putchar( '
    ' );
    	}
    	return 0;
    }
    
  • 相关阅读:
    node异步转同步(循环)
    三级省市区PCASClass.js插件
    微信公众号基础总结(待更新)
    ES6详解
    webpack配置
    高性能 CSS3 动画
    github上传口令
    纯css3 实现3D轮播图
    优美的js代码,拿去玩~
    关于列举属性用点还是用【】
  • 原文地址:https://www.cnblogs.com/crashed/p/13245883.html
Copyright © 2020-2023  润新知