ZROI#956

ZROI#956

ZROI#956
这题难死我了...
不过这题的\(55pts\)暴力被我校大佬们当成了\(set\)练习题,\(100pts\)是一个很妙的\(01trie\)做法.
\(Subtask1\)就模拟就行了,太水了不讲.
先讲一讲\(Subtask3\)吧,用一个\(multiset\)维护,不过要维护一个全局标记\(tag\),表示当前加过的数字的总和.
每次插入一个新数字\(x\)就插入\((x-tag+mod)%mod\),这是因为我们的每次查询/删除都要查询/删除\((x-tag+mod)%mod\).
一定要记得\((+mod)%mod\),笔者就是因为这个原因删除不存在的元素导致疯狂\(RE\).

再说一说\(Subtask2\)吧,这个同理,也是维护一个全局懒标记\(tag\),不过每次插入\(x\)的时候变成了插入\(x \:xor \:tag\),这是因为\(xor\)的逆操作是\(xor\).
查询和删除同理.

结合这两种算法和模拟总共可以得到\(55pts\)的分数,可谓十分不错.
\(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::set ;
using std::pair ;
using std::max ;
using std::min ;
using std::priority_queue ;
using std::vector ;
using std::multiset ;

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 = 5e5 + 100 ;

vector < int > v ;
multiset < int > s ; int t[N] , siz , types[5] ;
int n , q , x , opt , mod = pow ( 2 , 30 ) , tag ;

struct operators { int val , type ; } op[N] ;

inline void solve1 () {
    while ( q -- ) {
        opt = rint () ;
        if ( opt == 1 ) t[++siz] = rint () ;
        if ( opt == 2 ) {
            int pos ; x = rint () ;
            rep ( i , 1 , siz ) if ( t[i] == x ) { pos = i ; break ; }
            -- siz ; rep ( i , pos , siz ) t[i] = t[i+1] ;
        }
        if ( opt == 3 ) rep ( i , 1 , siz ) t[i] = ( t[i] + 1 ) % mod ;
        if ( opt == 4 ) { x = rint () ; rep ( i , 1 , siz ) t[i] ^= x ; }
    }
    std::sort ( t + 1 , t + siz + 1 ) ;
    rep ( i , 1 , siz ) printf ("%lld " , t[i] ) ;
}

inline void solve2 () {
    rep ( i , 1 , q ) {
        opt = op[i].type ;
        if ( opt == 1 ) s.insert ( op[i].val ^ tag ) ;
        if ( opt == 2 ) s.erase ( s.find ( op[i].val ^ tag ) ) ;
        if ( opt == 4 ) tag ^= op[i].val ;
    }
    for ( auto k : s ) v.pb ( k ^ tag ) ; std::sort ( v.begin () , v.end () ) ;
    for ( int k : v ) printf ("%lld " , k ) ;
    return ;
}

inline void solve3 () {
    rep ( i , 1 , q ) {
        opt = op[i].type ;
        if ( opt == 1 ) s.insert ( ( op[i].val - tag + mod ) % mod ) ;
        if ( opt == 2 ) s.erase ( s.find ( ( op[i].val - tag + mod ) % mod ) ) ;
        if ( opt == 3 ) ++ tag ;
    }
    for ( auto k : s ) v.pb ( ( k % mod + tag ) % mod ) ;
    std::sort ( v.begin () , v.end () ) ; for ( int k : v ) printf ("%lld " , k ) ;
}

signed main (int argc , char * argv[] ) {
    n = rint () ; q = rint () ;
    rep ( i , 1 , n ) { x = rint () ; s.insert ( x ) ; t[++siz] = x ; }
    if ( n <= 5e3 && q <= 5e3 ) solve1 () ; 
    else {
        rep ( i , 1 , q ) { op[i].type = rint () ; if ( op[i].type != 3 ) op[i].val = rint () ; ++ types[op[i].type] ; }
        if ( ! types[3] ) solve2 () ; else if ( ! types[4] ) solve3 () ;
    }
    return 0 ;
}

接下来是正解做法:
还是用全局懒标记维护异或操作.
但是\(+1\)之后再\(mod\: 2^{30}\)这个操作怎么处理呢?
你考虑,这个操作相当于是在二进制形式中寻找一个\(i\),使得\(a_1,a_2...a_{i-1}\)都是\(1\),而\(a_i\)\(0\),然后翻转\(a_1,a_2,a_3...a_{i-1},a_{i}\)即可.
这个问题,我们可以放到\(01Trie\)上去做,不过你可能会发现这个东西需要你从叶子去找一段连续的\(1\),这就很难办.
所以我们选择,从低位到高位建树,这样就是自然地从根节点找一段连续的\(1\)了.
加上异或操作之后,记得统计全局标记就行了.不过加上异或之后我们要找的就不一定是一段连续的\(1\),为了使异或对应关系一致,所以需要异或一个\(maxsize-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 X first
#define Y second
#define rint read<int>
#define int long long
#define pb push_back

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 = 3e5 + 100 ;
const int maxsize = ( 1 << 30 ) - 1 ;

vector < int > ans ;
int n , opt , u , v , q[33] , cnt , m ;
int ch[N<<5][2] , sum[(N<<5)] , tag ;

inline void insert (int cur , int val) {
    int now = 0 ;
    for (int i = 0 ; i < 30 ; ++ i) {
        int son = ( cur >> i ) & 1 ;
        if ( ! ch[now][son] ) ch[now][son] = ++ cnt ;
        now = ch[now][son] ;
    }
    sum[now] += val ; return ;
}

inline void reverse () {
    int now = 0 , siz = 0 , cur = maxsize ^ tag ;
    for (int i = 0 ; i < 30 ; ++ i) {
        int son = ( cur >> i ) & 1 ;
        q[++siz] = now ;
        if ( ! ch[now][son] ) break ;
        now = ch[now][son] ;
    }
    rep ( i , 1 , siz ) swap ( ch[q[i]][0] , ch[q[i]][1] ) ;
    return ;
}

inline void dfs (int cur , int dep , int val) {
    if ( dep >= 30 ) {
        rep ( i , 1 , sum[cur] ) ans.pb ( val ^ tag ) ;
        return ;
    }
    if ( ch[cur][0] ) dfs ( ch[cur][0] , dep + 1 , val ) ;
    if ( ch[cur][1] ) dfs ( ch[cur][1] , dep + 1 , val | ( 1 << dep ) ) ;
    return ;
}

signed main (int argc , char * argv[] ) {
    n = rint () ; m = rint () ; rep ( i , 1 , n ) insert ( rint () , 1 ) ;
    while ( m -- ) {
        int opt = rint () ;
        if ( opt == 1 ) insert ( rint () ^ tag , 1 ) ;
        if ( opt == 2 ) insert ( rint () ^ tag , - 1 ) ;
        if ( opt == 3 ) reverse () ;
        if ( opt == 4 ) tag ^= rint () ;
    }
    dfs ( 0 , 0 , 0 ) ; sort ( ans.begin () , ans.end () ) ;
    for (int k : ans ) printf ("%lld " , k ) ;
    system ("pause") ; return 0 ;
}
posted @ 2019-09-04 16:22  Phecda  阅读(92)  评论(0编辑  收藏  举报

Contact with me