CodeForces - 706D Vasiliy's Multiset (01字典树)

题目链接:

https://vjudge.net/problem/CodeForces-706D
http://codeforces.com/contest/706/status/D

题意:

       n次操作,三种操作,给定一个空集,插入一个数,删除一个数,查询给定数与集合中某一数的最大异或值;

分析:

       比较坑的是题目说了0始终存在于集合中,想一想这种情况给你一个数x,结果它和集合中的任意非零数的异或都小于它本身x,而0与x的异或是x,刚好是最大的,这样就必须一开始插入0;开始没看见题目这个条件,而且没考虑到0的这种情况,所以一直wa,而且我把十进制转化位32位存进去的时候,和转化位31、30位的结果截然不同,不知道什么原因;
       关于删除一个数,当你把一个十进制数转化位二进制存入进去的时候,每个二进制都有一个编号,每当你存入一个数,那么就会经过那个数对应二进制每一位一次,比如12与10分别是,1100和1011,那么插入的时候左边第一个1以及之前的零都是一样的(共用),在一起是经过两次,在第一个1之后会产生分支;那么你用一个数组记录经过这个数每一个二进制位的次数,当你要删除的时候,把次数减1即可,查询的时候,优先考虑相反(0就走1,1就走0)并且判断这条分支经过的次数是不是大于0,同时满足就可以走;

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;

const int inf=0x7f7f7f7f;
const int maxn=1e1+50;
const int N=5e6+50;
typedef long long ll;
typedef struct{
    ll u,v,next,w;
}Edge;
Edge e[N];

int cnt,head[N];

inline void add(int u,int v){
    e[cnt].u=u;
    e[cnt].v=v;
    //e[cnt].w=w;
    // e[cnt].f=f;
    e[cnt].next=head[u];
    head[u]=cnt++;
    // e[cnt].u=v;
    // e[cnt].v=u;
    // e[cnt].w=0;
    // e[cnt].f=-f;
    // e[cnt].next=head[v];
    // head[v]=cnt++;
}

inline int read()
{
    int x = 0;
    int f = 1;
    char c = getchar();
    while (c<'0' || c>'9')
    {    
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (c >= '0'&&c <= '9')
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x*f;
}
int q,t,num=1,trie[N][2],val[N],cot[N];
char c;

void insert(int x){
    int p=1;
    for(int i=31;i>=0;i--){
        int r=(x>>i)&1;
        if(i==31&&x==8)
            cout<<r<<endl;
        if(!trie[p][r]){
            trie[p][r]=++num;
        }
        p=trie[p][r];
        cot[p]++;
    }
    val[p]=x;
}

void delet(int x){
    int p=1;
    for(int i=31;i>=0;i--){
        int r=(x>>i)&1;
        p=trie[p][r];
        cot[p]--;
    }
}

int query(int x){
    int p=1,ans;
    for(int i=31;i>=0;i--){
        int r=(x>>i)&1;
        if(cot[trie[p][r^1]])p=trie[p][r^1];
        else p=trie[p][r];
    }
    //cout<<val[p]<<endl;
    return val[p]^x;
}


int main() {
    cin>>t;
    insert(0);
    while(t--){
        getchar();
        cin>>c>>q;
        if(c=='+'){
            insert(q);
        }
        else if(c=='-'){
            delet(q);
        }
        else if(c=='?'){
            cout<<query(q)<<endl;
        }
    }
    return 0;
}

(仅供个人理解)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值