CF817E Choosing TheCommander(01Trie)

题目链接

  题意:实现三种操作\(1.\)\(p\)加入集合中,\(2.将p\)从集合中删去,\(3.\)查询集合中所有的树在异或\(p\)之后有多少个数小于\(l\).
  思路:看到跟异或的统计数字问题,所以考虑用\(01Trie\)树来实现这些操作,将\(p\)加入到集合或从集合中删除,就是很正常的\(Trie\)树的操作,将每一个数的各个二进制位都存入到树中。查询操作,考虑\(l\)当前位是\(0/1\),如果是\(0\)的话异或不会改变该位,所以继续沿着当前的路径走下去,相反出现\(1\)就将\(0\)这一分支的答案统计下来,并向相反的方向走。

    constexpr int N = 5e6 + 10;
    #define int i64
    int tr[N][2], sum[N];
    int idx = 1;

    void add(int p, int z) {
        int u = 1;
        for (int i = 31; i >= 0; i--) {
            bool x = p & (1 << i);
            if (!tr[u][x]) tr[u][x] = ++idx;
            u = tr[u][x];
            sum[u] += z;
        }
    }

    int query(int p, int l) {
        int ans = 0, u = 1;
        for (int i = 31; i >= 0; i--) {
            bool x = p & (1 << i), y = l & (1 << i);
            if (y) ans += sum[tr[u][x]], u = tr[u][x ^ 1];
            else u = tr[u][x];
        }
        return ans;
    }

    signed main() {
        std::cin.tie(nullptr)->sync_with_stdio(false);
        int q; std::cin >> q;
        while(q--) {
            int op;
            std::cin >> op;
            int p; std::cin >> p;
            if (op == 1) {
                add(p, 1);
            } else if (op == 2) {
                add(p, -1);
            } else {
                int l; std::cin >> l;
                std::cout << query(p, l) << "\n";
            }
        }
    }
posted @ 2022-09-16 16:36  浅渊  阅读(23)  评论(0)    收藏  举报