E. Choosing The Commander

E. Choosing The Commander

题意:

q次询问(q<=1e5)每次询问对应三种操作中的一种

1 x 增添一个数x

2 x 删除一个数x

3 x l 询问现有的数中 异或上x的值小于l的个数

思路:

询问次数1e5 普通暴力每次遍历查找复杂度为On2 会TLE

故要想一个更优的方法

字典树 复杂度:Onlogn

对于每个增添的数 将其转换为二进制数 然后用字典树维护二进制01串 

插入一个数:

每一个数的二进制数代表一条延续下来的路径 就从高位到低位添加 如果延续下来的当前位上有路径 直接让对应的cnt增加 否则 新添一个节点

删除一个数:

直接将x对应的每位的0或1的cnt减少

询问一个数:

x l 记录x 和 l对应二进制位位上的数 记为 bit1 bit2 字典树上的数该位上是 bit

1. 如果 bit2 == 0: 

      若 bit1 == 0  :bit == 0  bit1 ^ bit == bit2就继续寻找下一位

                              bit == 1    1 ^ 0 = 1 > 0 不符合了不能继续

     若 bit1 == 1  :     bit == 0  bit1 ^ bit > bit2 不符合了不能继续

                                bit == 1  bit1 ^ bit == bit2 继续找下一位

2. 如果bit2 == 1:

     若bit1 == 0   :   bit == 0    bit1 ^ bit < bit2 满足 该节点0的个数贡献给答案

                              bit == 1    bit1 ^ bit == bit2就继续寻找下一位

     若 bit1 == 1  :     bit == 0  bit1 ^ bit == bit2 就继续寻找下一位

                                bit == 1  bit1 ^ bit < bit2 满足 该节点0的个数贡献给答案

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

const ll inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-4;
const int N = 1e6 + 5;
const int M = 1e5 + 5;
const int mod = 1e9 + 7;
int n, a[N], x, op, l;
//cnt储存当前节点0 和 1的个数
//son储存当前节点的子节点的编号
struct node {
    int cnt[2] = { 0 };
    int son[2] = { 0 };
}tree[M << 5];
//序号
int tot = 0;

//插入一个数
void insert(int x) {
    int p = 0;
        //从高位到低位更新
    for (int i = 31; i >= 0; i--) {
                //取出当前位
        int bit = (x >> i) % 2;
                //没有该节点 新建一个节点
        if (!tree[p].son[bit]) {
            tree[p].son[bit] = ++tot;
            tree[p].cnt[bit]++;
        }
        else tree[p].cnt[bit]++;
                //往下
        p = tree[p].son[bit];
    }
}

//删除一个数
void delet(int x) {
    int p = 0;
    for (int i = 31; i >= 0; i--) {
                //取出当前位
        int bit = (x >> i) % 2;
        tree[p].cnt[bit]--;
        p = tree[p].son[bit];
    }
}

int query(int x, int l) {
    int p = 0, ans = 0;
    for (int i = 31; i >= 0; i--) {
        int bit1 = (x >> i) % 2;
        int bit2 = (l >> i) % 2;
        if (bit2 == 0) {//当bit2 == 1时 只有相等和大于的情况 那就直接相等的情况往后找
            int bit = bit1 ^ bit2;
            p = tree[p].son[bit];
                        //后面没有节点了
            if (p == 0) break;
        }
        else {//当bit2等于1是 就只有小于和等于的情况 那就将小雨的情况的cnt加给答案 然后在等于情况继续往下找
            int bit = bit1 ^ bit2;
            if (bit == 0) {
                ans += tree[p].cnt[1];
                p = tree[p].son[bit];
                if (p == 0) break;
            }
            else {
                ans += tree[p].cnt[0];
                p = tree[p].son[bit];
                if (p == 0) break;
            }
        }
    }
    return ans;
}

void solve()
{
    cin >> n;
    while (n--) {
        cin >> op;
        if (op == 1) {
            cin >> x;
            insert(x);
        }
        else if (op == 2) {
            cin >> x;
            delet(x);
        }
        else {
            cin >> x >> l;
            int ans = query(x, l);
            cout << ans << "\n";
        }
    }
}

int main()
{
    IOS;
    int t = 1;
    //cin >> t;
    while (t--)
    {
        solve();
    }
}

 

 

                           

posted @ 2022-04-28 23:03  Yaqu  阅读(39)  评论(0)    收藏  举报