Codeforces Round #367 (Div. 2) D. Vasiliy's Multiset (TireTree之位字典树)

本文解析了CodeForces竞赛中一道关于multiset的操作题目,通过构建30层字典树的方法实现对multiset的增删查操作,特别是对求解特定抑或运算的最大结果进行了详细的说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://codeforces.com/contest/706/problem/D

题意:

对一个multiset(集合中的元素可以重复的set)有三种操作——

+ x: 增加元素x

- x: 减少元素x

?x: 求multiset中与x抑或得到的数最大为多少

已知0总是存在于multiset中。

 

分析:

时限为4s。

1 ≤ xi ≤ 109,由于109≈(2103≈230,103<210,也就是说x最多为30位

那么对数的每一位建立字典树,即最多为30层。

当要找与x抑或得到的结果最小的数时,只需尽可能找与x的每个数位相反的路径,

即可得到multiset中的那个数。

 

这样每个数都按照最大数可能的位数30来构建字典树,方便处理。

#include<cstdio>
#include<algorithm>
#include<map>
#include<cstring>
#include<string>
#include<iostream>
#include<set>
#include<vector>
#include<cmath>

using namespace std;

typedef long long ll;
const int mod = 1000000007;
const int maxn = 200010;
const int len = 30;

struct node
{
    int cnt;
    int next[2];
}tree[maxn*len];

int num;

void init()
{
    memset(tree,-1,sizeof(tree));
    num = 0;
}
void add(int x)
{
    int now = 0;
    bool k;
    for(int i=len-1;i>=0;i--)
    {
        k = (x>>i)&1;
        if(tree[now].next[k]==-1)
            tree[now].next[k] = ++num;
        now = tree[now].next[k];
        tree[now].cnt = tree[now].cnt==-1?1:(tree[now].cnt+1);
    }
}

void del(int x)
{
    int now = 0;
    bool k;
    for(int i=len-1;i>=0;i--)
    {
        k = (x&(1<<i));
        now = tree[now].next[k];
        tree[now].cnt--;
    }
}

int query(int x)
{
    int now = 0,ret = 0;
    bool k;
    for(int i=len-1;i>=0;i--)
    {
        k = (x&(1<<i));
        if(tree[now].next[!k]!=-1 && tree[tree[now].next[!k]].cnt>0)
            k = !k;
        now = tree[now].next[k];
        ret = ret|(k<<i);
    }
    return ret;
}

int main()
{
    int q;
    char op[2];
    int x;
    while(~scanf("%d",&q))
    {
        init();
        add(0);
        for(int i=0;i<q;i++)
        {
            scanf("%s%d",op,&x);
            if(op[0]=='+')
                add(x);
            else if(op[0]=='-')
                del(x);
            else
            {
                int t = query(x);
                printf("%d\n",(t^x));
            }
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/hadis-yuki/p/5768439.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值