维护一棵Trie树,每个节点记一下前缀目前出现的次数cnt,每个节点开一个vector记录出现次数超过i的最早操作。只有当cnt>a[p].size()时更新vector就好啦。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 6000000
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,owo=0,cnt[N],son[N][10],now,rt=0,lastans=0;
char s[100];
vector<int>a[N];
inline void ins(int &p,int x){
if(!p) p=++owo;
cnt[p]++;if(cnt[p]>a[p].size()) a[p].push_back(now);
if(!s[x]) return;ins(son[p][s[x]-'a'],x+1);
}
inline void del(int p,int x){
cnt[p]--;
if(!s[x]) return;del(son[p][s[x]-'a'],x+1);
}
inline int ask(int p,int x,int k){
if(!p) return -1;
if(s[x]) return ask(son[p][s[x]-'a'],x+1,k);
if(k>=a[p].size()) return -1;return a[p][k];
}
int main(){
// freopen("a.in","r",stdin);
n=read();
for(now=1;now<=n;++now){
int op=read();scanf("%s",s+1);
if(op==1) ins(rt,1);
else if(op==2) del(rt,1);
else{
int a=read(),b=read(),c=read();
lastans=ask(rt,1,((ll)a*lastans+b)%c);
printf("%d\n",lastans);if(lastans<0) lastans=-lastans;
}
}return 0;
}