• Codeforces Round #367 (Div. 2) D. Vasiliy's Multiset (0/1-Trie树)


    Vasiliy's Multiset

    题目链接:

    http://codeforces.com/contest/706/problem/D

    Description

    ``` Author has gone out of the stories about Vasiliy, so here is just a formal task description.

    You are given q queries and a multiset A, initially containing only integer 0. There are three types of queries:

    "+ x" — add integer x to multiset A.
    "- x" — erase one occurrence of integer x from multiset A. It's guaranteed that at least one x is present in the multiset A before this query.
    "? x" — you are given integer x and need to compute the value , i.e. the maximum value of bitwise exclusive OR (also know as XOR) of integer x and some integer y from the multiset A.
    Multiset is a set, where equal elements are allowed.

    </big>
    
    
     
    
    
    
    
    ##Input
    <big>
    

    The first line of the input contains a single integer q (1 ≤ q ≤ 200 000) — the number of queries Vasiliy has to perform.

    Each of the following q lines of the input contains one of three characters '+', '-' or '?' and an integer xi (1 ≤ xi ≤ 109). It's guaranteed that there is at least one query of the third type.

    Note, that the integer 0 will always be present in the set A.

    </big>
    
    
    
    
    
    
    ##Output
    <big>
    

    For each query of the type '?' print one integer — the maximum value of bitwise exclusive OR (XOR) of integer xi and some integer from the multiset A.

    </big>
    
    
     
     
    ##Examples
    <big>
    

    input
    10

    • 8
    • 9
    • 11
    • 6
    • 1
      ? 3
    • 8
      ? 3
      ? 8
      ? 11
      output
      11
      10
      14
      13
    </big>
    
    
    ##Source
    <big>
    Codeforces Round #367 (Div. 2)
    </big>
    
    
    
    
    <br/>
    ##题意:
    <big>
    维护一个multiset:
    操作1:插入一个数字
    操作2:删除指定数字
    操作3:给出一个x,求集合中的一个元素y,使得 x XOR y 最大.
    </big>
    
    
    <br/>
    ##题解:
    <big>
    由于异或前后的值不能保持单调性,所以排序和线段树都不好处理.
    这里需要用一个 0/1-Trie树 来维护.
    对于集合中的数用二叉树中的结点来表示其二进制位.
    ①插入:开辟一些新的树结点.
    ②删除:找到对应结点赋成NULL.  删除时有几点需要注意:
    集合允许重复,所以可以记录每个数出现的次数,当集合中仅有一个x时才删除. 
    把最底端的叶节点删除后,要递归更新其父结点的状态,否则在匹配时可能会进入不存在的结点.
    ③匹配:先把x按位取反,从高位到低位在二叉树中匹配x,按能匹配时尽量匹配的原则往下走. 这样可以保证结果从高位到低位有尽量多的位不相同,即异或结果最大.
    注意:初始时集合中有个0,一开始忘了这个,RE了2发.
    </big>
    
    
    
    
    <br/>
    ##代码:
    ``` cpp
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <set>
    #include <stack>
    #include <vector>
    #include <list>
    #define LL long long
    #define eps 1e-8
    #define maxn 101000
    #define mod 100000007
    #define inf 0x3f3f3f3f
    #define mid(a,b) ((a+b)>>1)
    #define IN freopen("in.txt","r",stdin);
    using namespace std;
    
    class Trie
    {
        public:
        Trie *next[2];
        Trie() {
            memset(next,NULL,sizeof(next));
        }
    };
    
    Trie *root;
    
    void Insert(LL n)
    {
        Trie *p = root;
        for(int i=31;i>=0;i--)
        {
            int id = (n >> i) & 1;
            if(p->next[id] == NULL)
                 p->next[id] = new Trie();
            p = p->next[id];
        }
    }
    
    
    int Delete(Trie *p, LL n, int i)
    {
        if(i < 0) return 1;
        int id = (n >> i) & 1;
        int ret = Delete(p->next[id], n, i-1);
        if(ret) p->next[id] = NULL;
        if(p->next[0] == NULL && p->next[1] == NULL)
            return 1;
        return 0;
    }
    
    LL Match(LL m)
    {
        m = ~m;
        LL ans = 0;
        Trie *p = root;
        for(int i=31;i>=0;i--) {
            ans <<= 1;
            int bit = (m >> i) & 1;
            if(bit) {
                if(p->next[1]) {
                    p = p->next[1];
                    ans++;
                }
                else {
                    p = p->next[0];
                }
            }
            else {
                if(p->next[0]) {
                    p = p->next[0];
                }
                else {
                    p = p->next[1];
                    ans++;
                }
            }
        }
        return ans;
    }
    
    map<LL, int> occ;
    
    int main(int argc, char const *argv[])
    {
        //IN;
    
        int q;
        while(scanf("%d", &q) != EOF)
        {
            root = new Trie();
            occ.clear();
            Insert(0LL);
            occ[0] = 1;
            while(q--)
            {
                getchar();
                char op; LL val;
                op = getchar();
                scanf("%I64d", &val);
    
                if(op == '+') {
                    if(!occ[val]) {
                        occ[val] = 1;
                        Insert(val);
                    }
                    else occ[val]++;
                }
                else if(op == '-') {
                    if(occ[val] == 1) Delete(root, val, 31);
                    occ[val]--;
                } else {
                    printf("%I64d
    ", Match(val)^val);
                }
            }
        }
    
        return 0;
    }
    
  • 相关阅读:
    银丰新融:搭建名单监控管理系统,落实“三反”政策
    动手实操丨RC522射频卡模块与IC卡完成充值消费查询的技术实现思路
    Open Harmony移植:build lite配置目录全梳理
    设备如何使用go sdk轻松连接华为云IoT平台?
    什么是隐私计算,它是怎样保护我们的隐私安全?
    聊聊如何在华为云IoT平台进行产品开发
    《Mybatis 手撸专栏》第7章:SQL执行器的定义和实现
    校招、社招,这么写简历,字节一定能进去!
    《Mybatis 手撸专栏》第6章:数据源池化技术实现
    简单了解 TiDB 架构
  • 原文地址:https://www.cnblogs.com/Sunshine-tcf/p/5793604.html
Copyright © 2020-2023  润新知