新人刚学OI,63分卡空间救助
查看原帖
新人刚学OI,63分卡空间救助
281668
FOX_konata楼主2022/4/5 19:21

RT,本人代码:

#include <bits/stdc++.h>
// #pragma GCC optimize(2)
#define ll long long
#define For( i , j , k ) for( int i = ( j ) ; i <= ( k ) ; ++ i )
using namespace std;
template < typename T >
inline T read( T &num ){
    num = 0 ; T f = 1 ; char c = ' ';
    while( c < '0' || c > '9' ) if( ( c = getchar() ) == '-' ) f = -1;
    while( c >= '0' && c <= '9' ) num = ( num << 1 ) + ( num << 3 ) + ( c ^ 48 ) , c = getchar();
    num *= f; return num;
}
//-------------------------Fastio end-------------------------//
const int maxn = 5e5 + 5;
const int INF = ( 1ll << 29 );
/*
我的思路,有问题欢迎dalao指出:
对于第二种操作,我们可以维护一个用线段树维护一个lst[ i ]的最大值和a[ i ]的最大值和最小值
lst[ i ]: 当前a[ i ]这个数之前出现的下标
可以发现当区间[l,r]为值域上连续的一段时,当且仅当:
( max - min + 1 ) == ( r - l + 1 ) && max{ lst[ i ] } < l }
考虑修改操作,我们再维护一个lst[ i ]
nxt[ i ]: 当前a[ i ]这个数下次再出现的下标
每次我们修改一个数x为y时,只会修改5个数的nxt/lst
分别是nxt[ x ] , lst[ x ] , x , x前面最靠近它的y ,x的后面最靠近它的y
前两种可以O(1)解决,对于后两种我们给每个数a[ i ]维护一个set,内存它的下标,二分即可
别忘了给a[ i ]离散化
*/
int n , m;
int a[ maxn << 1 ];
struct Node{
    int st; bool nd;
    bool operator < ( const Node &y ) const{ return st < y.st; }
    bool operator < ( const int &y ) const{ return st < y; }
    bool operator == ( const int &y ) const{ return st == y; }
    bool operator == ( const Node &y ) const{ return st == y.st; }
}b[ maxn << 1 ];
int cnt_b;
int nxt[ maxn << 1 ] , lst[ maxn << 1 ];
inline int bfind( int x ){ return lower_bound( b + 1 , b + cnt_b + 1 , x ) - b; }
set< int > buc[ maxn << 1 ];
struct Ask{ int opt , x , y; }ask[ maxn ];
struct Segment_Tree{//线段树
    #define ls ( p << 1 )
    #define rs ( p << 1 | 1 )
    struct Tree{
        int pmaxs , maxs , mins;
        Tree operator + ( const Tree &y ) const{
            Tree ans;
            ans = Tree{ max( pmaxs , y.pmaxs ) , max( maxs , y.maxs ) , min( mins , y.mins ) };
            return ans;
        } 
    }trees[ maxn << 2 ];
    inline void push_up( int p ){ trees[ p ] = trees[ ls ] + trees[ rs ]; }
    inline void build( int l , int r , int p ){
        trees[ p ] = Tree{ -INF , -INF , INF };
        if( l == r ){
            trees[ p ] = Tree{ lst[ l ] , a[ l ] , a[ l ] };
            return ;
        }
        int mid = l + r >> 1;
        build( l , mid , ls ) , build( mid + 1 , r , rs );
        push_up( p );
    }
    inline void update( int l , int r , int x , int kp , int k , int p ){
        if( l == r ){
            if( k == INF ) trees[ p ].pmaxs = kp;
            else trees[ p ] = Tree{ kp , k , k };
            return ;
        }
        int mid = l + r >> 1;
        if( x <= mid ) update( l , mid , x , kp , k , ls );
        else update( mid + 1 , r , x , kp , k , rs );
        push_up( p );
    }
    inline Tree query( int l , int r , int x , int y , int p ){
        if( x <= l && r <= y ) return trees[ p ];
        int mid = l + r >> 1;
        if( y <= mid ) return query( l , mid , x , y , ls );
        else if( mid < x ) return query( mid + 1 , r , x , y , rs );
        return query( l , mid , x , mid , ls ) + query( mid + 1 , r , mid + 1 , y , rs );
    }
}seg;
inline bool check( int l , int r ){
    Segment_Tree :: Tree ans = seg.query( 1 , n , l , r , 1 );
    if( ans.maxs - ans.mins + 1 == r - l + 1 && ans.pmaxs < l ) return true;
    return false;
}
inline void upd( int x , int y ){
    nxt[ lst[ x ] ] = nxt[ x ];
    lst[ nxt[ x ] ] = lst[ x ];//要修改
    seg.update( 1 , n , nxt[ x ] , lst[ x ] , INF , 1 );
    buc[ a[ x ] ].erase( x );
    a[ x ] = y;
    set< int > :: iterator it = buc[ y ].upper_bound( x );
    it --; lst[ x ] = *it;//要修改
    seg.update( 1 , n , x , lst[ x ] , y , 1 );
    it ++; if( it != buc[ y ].end() ) nxt[ x ] = *it;
    nxt[ lst[ x ] ] = lst[ nxt[ x ] ] = x;//要修改
    seg.update( 1 , n , nxt[ x ] , x , INF , 1 );
    buc[ y ].insert( x );
}
int main(){
    
    // freopen( "data.in" , "r" , stdin );
    // freopen( "data.out" , "w" , stdout );

    read( n ) , read( m );
    For( i , 1 , n ) b[ ++ cnt_b ] = Node{ read( a[ i ] ) , 0 };//0为属于a
    For( i , 1 , m ){
        read( ask[ i ].opt ) , read( ask[ i ].x ) , read( ask[ i ].y );
        if( ask[ i ].opt == 1 ) b[ ++ cnt_b ] = Node{ ask[ i ].y , 1 };//1为属于询问操作
    }
    sort( b + 1 , b + cnt_b + 1 );
    cnt_b = unique( b + 1 , b + cnt_b + 1 ) - b - 1;//b数组离散化
    For( i , 1 , n ) a[ i ] = bfind( a[ i ] );
    For( i , 1 , m ) if( ask[ i ].opt == 1 ) ask[ i ].y = bfind( ask[ i ].y );
    int cnt_a = n;
    For( i , 1 , cnt_b ){
        buc[ i ].insert( 0 );
        if( !b[ i ].nd ) a[ ++ cnt_a ] = i;//把b数组中属于a的在a中复制一遍,就不用特判边界了
    }
    For( i , 1 , cnt_a ){
        lst[ i ] = *buc[ a[ i ] ].rbegin();
        nxt[ lst[ i ] ] = i;
        buc[ a[ i ] ].insert( i );
    }
    seg.build( 1 , n , 1 );
    For( i , 1 , m ){
        if( ask[ i ].opt == 1 ) upd( ask[ i ].x , ask[ i ].y );
        else puts( check( ask[ i ].x , ask[ i ].y ) ? "damushen" : "yuanxing" );
    }
	return 0;
}

新人刚学OI,求助

2022/4/5 19:21
加载中...