CodeForces 714C Sonya and Queries(字典树/思维)

Description

Today Sonya learned about long integers and invited all her friends to share the fun. Sonya has an initially empty multiset with integers. Friends give her t queries, each of one of the following type:

 +  ai — add non-negative integer ai to the multiset. Note, that she has a multiset, thus there may be many occurrences of the same integer.
 -  ai — delete a single occurrence of non-negative integer ai from the multiset. It’s guaranteed, that there is at least one ai in the multiset.
? s — count the number of integers in the multiset (with repetitions) that match some pattern s consisting of 0 and 1. In the pattern, 0 stands for the even digits, while 1 stands for the odd. Integer x matches the pattern s, if the parity of the i-th from the right digit in decimal notation matches the i-th from the right digit of the pattern. If the pattern is shorter than this integer, it’s supplemented with 0-s from the left. Similarly, if the integer is shorter than the pattern its decimal notation is supplemented with the 0-s from the left.
For example, if the pattern is s = 010, than integers 92, 2212, 50 and 414 match the pattern, while integers 3, 110, 25 and 1030 do not.

Input

The first line of the input contains an integer t (1 ≤ t ≤ 100 000) — the number of operation Sonya has to perform.

Next t lines provide the descriptions of the queries in order they appear in the input file. The i-th row starts with a character ci — the type of the corresponding operation. If ci is equal to ‘+’ or ‘-’ then it’s followed by a space and an integer ai (0 ≤ ai < 1018) given without leading zeroes (unless it’s 0). If ci equals ‘?’ then it’s followed by a space and a sequence of zeroes and onse, giving the pattern of length no more than 18.

It’s guaranteed that there will be at least one query of type ‘?’.

It’s guaranteed that any time some integer is removed from the multiset, there will be at least one occurrence of this integer in it.

Output

For each query of the third type print the number of integers matching the given pattern. Each integer is counted as many times, as it appears in the multiset at this moment of time.

Examples

input
12
+ 1
+ 241
? 1
+ 361
- 241
? 0101
+ 101
? 101
- 101
? 101
+ 4000
? 0
output
2
1
2
1
1
input
4
+ 200
+ 200
- 200
? 0
output
1

题目大意

存在一个多重集,+代表向里添加一个元素,-代表从中减去这样一个元素,?代表查询多重集中满足这个一个01串的数字有多少个,其中0代表该位是偶数,1代表该位是奇数,然后对于多重集中的数字从后向前进行判断,位数不够时补前导0.

解题思路

1.字典树,每个节点含有0、1两个子节点,对于每一个串都是从后向前遍历进行建树,+时节点标记值+1,-时减1,访问时输出节点标记值。不过需要注意的是要考虑查询串较短需要补前导0 的情况,解决方法就是建树和查询时都先给子串补上前导0.
2.将元素处理成01串标记每一位是偶数还是奇数,然后按照二进制的形式将值存储起来,直接放在数组中再进行访问就可以了,大神的思路永远都是如此优秀.
可能是世上没有神,所以创造了优秀的程序猿/(ㄒoㄒ)/~~

代码实现

1.字典树

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);\
cin.tie(0);\
cout.tie(0);
typedef long long ll;
int MAXN =2;
char str1[20];
struct Trie
{
    int num;
    Trie *next[2];
}root;
void insert_trie(char *str,bool mark)
{
    int len = strlen(str);
    Trie *p = &root;
    Trie *q;
    for(int i = 0; i < len; i++)
    {
        int id = (str[i]-'0')%2;
        if(p->next[id] == NULL)
        {
            q = (Trie *)malloc(sizeof(root));
            q->num = 1;
            for(int j = 0; j < MAXN; j++)
                q->next[j] = NULL;
            p->next[id] = q;
            p = p->next[id];
        }
        else
        {
            if(mark==1)
                p->next[id]->num--;
            else
                p->next[id]->num++;
            p = p->next[id];
        }
    }
}
int findTrie(char *str)
{
    int len = strlen(str);
    Trie *p = &root;
    for(int i = 0; i < len; i++)
    {
        int id = str[i]-'0';
        p = p->next[id];
        if(p == NULL)
            return 0;
    }
    return p->num;
}
int main()
{
    IO;
    int n;
    char ch;
    cin>>n;
    while(n--)
    {
        cin>>ch>>str1;
        reverse(str1,str1+strlen(str1));
        for(int i=(int)strlen(str1);i<=18;i++)
            str1[i]='0';
        if(ch=='+')
            insert_trie(str1,0);
        else if(ch=='-')
            insert_trie(str1,1);
        else
            cout<<findTrie(str1)<<endl;
    }
    return 0;
}

2.思维

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);\
cin.tie(0);\
cout.tie(0);
typedef long long ll;
int num[1<<18];
char str[20];
int main()
{
    IO;
    int n;
    char ch;
    cin>>n;
    while(n--)
    {
        cin>>ch>>str;
        int countt=0;
        for(int i=0;i<(int)strlen(str);i++)
            countt=countt*2+(str[i]-'0')%2;
        if(ch=='?') cout<<num[countt]<<endl;
        else
            ch=='+'?num[countt]++:num[countt]--;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值