【哈希】Gym - 102448 - C - Call from Mendes

题目链接http://codeforces.com/gym/102448/problem/C


题意

三种操作,一共有 Q Q Q个:

  • 1    X 1\;X 1X:在字典里插入字符串 X X X
  • 2    X 2\;X 2X:在字典里删除字符串 X X X
  • 3    X 3\; X 3X:输出字典中最短的且前缀是 X X X 的下标。如果有多个字符串,输出字典序最小的。

字符串的下标是指该串被插入时的时间。

输入中所有的字符串长度和不超过 1 0 6 10^6 106


题解

第一眼感觉是可持久化AC自动机?不会啊。然后就看到了这个条件:所有的字符串长度和不超过 1 0 6 10^6 106 ,决定乱搞。

对每个长度开一个 m a p < h a s h , s e t > [ i ] map<hash, set>[i] map<hash,set>[i],表示存在一个 s e t set set 的字符串满足长度为 i i i 的前缀哈希值是 h a s h hash hash

s e t set set 里记录一下字符串的信息,比如长度啊,字典序啊,下标啊。这个字典序我的求法就比较夸张,直接全部读进来,离散排个序。

然后三种操作只要对应的把 m a p map map s e t set set 维护好就行了。

这绝对不是标准做法 但是我过了


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+7;
int q;
int op[N];
string s[N],ss[N];
int px[N];
int er[N];
struct Node{
    int id,len,p;
    bool operator<(const Node k)const{
        if(len==k.len) return p<k.p;
        return len<k.len;
    }
};
unordered_map<unsigned long long,set<Node>>mp[N*10];
int main(){
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        scanf("%d",&op[i]);
        if(op[i]==2) scanf("%d",&er[i]),ss[i]=ss[er[i]];
        else cin>>ss[i];
        s[i]=ss[i];
    }
    sort(ss+1,ss+1+q);
    for(int i=1;i<=q;i++){
        px[i]=lower_bound(ss+1,ss+1+q,s[i])-ss;
    }
    for(int i=1;i<=q;i++){
        if(op[i]==1){
            unsigned long long h=0;
            for(int j=0;j<s[i].length();j++){
                h=h*233+s[i][j]-'a';
                mp[j][h].insert((Node){i,s[i].length(),px[i]});
            }
        }
        else if(op[i]==2){
            unsigned long long h=0;
            h=0;
            for(int j=0;j<s[i].length();j++){
                h=h*233+s[i][j]-'a';
                mp[j][h].erase((Node){er[i],s[i].length(),px[i]});
            }
        }
        else{
            unsigned long long h=0;
            for(int j=0;j<s[i].length();j++){
                h=h*233+s[i][j]-'a';
            }
            if(mp[s[i].length()-1][h].empty()) printf("-1\n");
            else printf("%d\n",(*mp[s[i].length()-1][h].begin()).id);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值