CodeForces 706D Vasiliy's Multiset (字典树查询+贪心)

题意:最开始的时候有一个集合,集合里面只有一个元素0,现在有q次操作,操作分为3种:

+ x: 表示向集合中添加一个元素x

- x:表示删除集合中值为x的一个元素

? x:表示查询集合中与x异或的最大值为多少

析:这是一个字典树的应用,不过确实没看出来。。。。主要思想是这样,先用10进制数,转成二进制数,记下每个结点的0,1的个数,这样增加和删除,就是对01的删除,

剩下的就是查询,那么尽量让0和1XOR是最大的,所以,对于给定数,我们要去尽量他的XOR数,如果找到就加上,找不到,就找下一个。这样就是最大的。

代码如下:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <stack>
using namespace std;

typedef long long LL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 0x3f3f3f3f3f3f;
const LL LNF = 100000000000000000;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 4e6 + 5;
const int mod = 1e9 + 7;
const char *mark = "+-*";
const int dr[] = {-1, 0, 1, 0};
const int dc[] = {0, 1, 0, -1};
int n, m;
inline bool is_in(int r, int c){
    return r >= 0 && r < n && c >= 0 && c < m;
}
inline LL Max(LL a, LL b){  return a < b ? b : a; }
inline LL Min(LL a, LL b){  return a > b ? b : a; }
inline int Max(int a, int b){  return a < b ? b : a; }
inline int Min(int a, int b){  return a > b ? b : a; }
int ch[maxn][2];
int t[maxn];
int cnt = 0;

void add(int x){
    int k = 1;
    for(int i = 30; i >= 0; --i){
        int j = ((1<<i) & x) > 0;
        if(!ch[k][j])  ch[k][j] = ++cnt;
        k = ch[k][j];
        ++t[k];
    }
}

void del(int x){
    int k = 1;
    for(int i = 30; i >= 0; --i){
        int j = ((1<<i) & x) > 0;
        k = ch[k][j];
        --t[k];
    }
}

int query(int x){
    int k = 1;
    int ans = 0;
    for(int i = 30; i >= 0; --i){
        int j = ((1<<i) & x) == 0;
        if(t[ch[k][j]]){
            ans |= (1<<i);
            k = ch[k][j];
        }
        else k = ch[k][1-j];
    }
    return ans;
}

int main(){
    while(scanf("%d", &n) == 1){
        cnt = 1;
        memset(ch, 0, sizeof(ch));
        memset(t, 0, sizeof(t));
        add(0);
        while(n--){
            char s[3];
            int x;
            scanf("%s %d", s, &x);
            if(s[0] == ‘+‘)  add(x);
            else if(s[0] == ‘-‘)  del(x);
            else   printf("%d\n", query(x));
        }
    }
    return 0;
}

  

CodeForces 706D Vasiliy's Multiset (字典树查询+贪心)

时间: 2024-11-10 07:16:52

CodeForces 706D Vasiliy's Multiset (字典树查询+贪心)的相关文章

Codeforces 706D Vasiliy&#39;s Multiset(可持久化字典树)

[题目链接] http://codeforces.com/problemset/problem/706/D [题目大意] 要求实现一个集合中的三个操作,1:在集合中加入一个元素x,2:从集合中删除一个元素x(保证x存在),3:要求从集合中选出一个数,使得其与给出的数x的异或值最大,输出这个异或值. [题解] 可以将所有的以二进制形式存在01字典树上,删除即插入权值为-1的二进制串,对于异或值最大的操作,我们只要在字典树上按位贪心,从最高位开始尽量保证该位存在最后就能得到答案.写代码的时候直接写了

(字典树)codeforces - 706D Vasiliy&#39;s Multiset

原题链接:http://codeforces.com/problemset/problem/706/D 题意:需要你模拟一个多重集合(初始拥有0),该集合拥有三个功能 1.+ x  增加一个x(可以同时存在多个x,因为是多重集合) 2.-  x 去掉一个x 3.? x  输出在这个集合中和x异或最大的值. 分析:有20万个操作,很容易想到树形数据结构,我们可以看到每个x最多只有10^9,而1<<30比10^9大一点,所以10^9次方最多就是29位的01串,可以维护一个字典树. 每个节点有两个分

CodeForces 706D Vasiliy&#39;s Multiset

字典树. 比较经典的题目了.把每一个数字都插入到字典树中,询问的时候如果$x$的第$i$位是$p$,那么尝试着在字典树上往$pXOR1$的节点走下去,没有$pXOR1$节点的话再走$p$的.删除操作的话可以记录一下每一个节点出现了几次,$Insert$的时候$s[p].cnt++$,$Delete$的时候$s[p].cnt--$,如果发现$s[p].cnt==0$,那么将以$p$为根的树全删了,也就是$p$的$father$到$p$的路标为$-1$. #pragma comment(linker

基础字典树查询前缀

题目1 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一本词典,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能对于每一个我给出的字符串,都在这个词典里面找到以这个字符串开头的所有单词呢?” 身经百战的小Ho答道:“怎么会不能呢!你每给我一个字符串,我就依次遍历词典里的所有单词,检查你给我的字符串

利用01字典树查询最大异或值

01字典树的是只含有0和1两种字符的字典树,在使用它的时候,把若干数字转成二进制后插入其中 在查询树中的哪个数字和给定数字有最大异或值的时候,从根开始贪心查询就ok了 HDU4825是一道裸题:给出n个数和m次询问,每次询问给出一个数x,问在n个数中哪个数与x异或值最大 1 #include<cstdio> 2 #include<cstring> 3 const int maxn=1000005; 4 int n,m,rt; 5 int a[maxn],v[3500005],s[3

codeforces gym #101161F-Dictionary Game(字典树+树上删边游戏)

题目链接: http://codeforces.com/gym/101161/attachments 题意: 给一个可以变化的字典树 在字典树上删边 如果某条边和根节点不连通那么这条边也删除 谁没得删就输了 数据范围: $1\leq n \leq 100000$ $1\leq q \leq 100000$ $1\leq |s| \leq 40$ 分析: ac代码: #include<bits/stdc++.h> using namespace std; #define ll long long

Codeforces 577E Ann and Half-Palindrome 字典树

题目链接 题意: 若一个字符串是半回文串,则满足第一位和最后一位相等, 第三位和倒数第三位相等,如此类推. 给定一个字符串s,输出s的所有子串中的半回文串字典序第k大的 字符串. good[i][j] 表示 s(i,j) 是半回文串. 把这些回文串插到字典树里 在字典树上找第k个叶子节点. 插入时:插入以i点开头的所有半回文串. #include <iostream> #include <string> #include <vector> #include <cs

UVALive 7712 Confusing Manuscript 字典树 查询与s的编辑距离为1的字符串数量

/** 题目:UVALive 7712 Confusing Manuscript 链接:https://vjudge.net/problem/UVALive-7712 题意:给定n个不同的字符串,f(i)表示第i个字符串和其他字符串的编辑距离为1的个数. 编辑距离为1表示两个字符串其中一个可以通过删除任意位置某一个字符或者增加任意位置某一个字符或者替换任意位置某一个字符之后,两者匹配. 输出f(i)最大的字符串,如果f(i)==f(j) (i<j) 输出第i个字符串. 思路:字典树 主要是处理细

Codeforces 1285D Dr. Evil Underscores(字典树,dp)

传送门 题意: 有一个长度为 \(n\ (1\leq n\leq 10^5)\)的整数序列 \(a_1,\cdots,a_n\ \ (0\leq a_i\leq 2^{30}-1)\),你需要找到一个非负整数 \(X\) 使得 \(\max(a_i\oplus X)\)最小,其中 \(\oplus\) 为按位异或运算. 输入这个序列,输出\(\max(a_i\oplus X)\)的最小值. 思路: 1.数组中的每个数的二进制下的某位(第k位)都是0或者是1,那么x的第k位取值是0或者1,使得答案