前言
这是我第一次在cf比赛时做出AC自动机的题,而且是在比赛最后30秒AC的,特发博客纪念一波。
题意
中文简单说一下就是:有n个字符串,初始值为0。有两种操作,操作1是将序号为i的字符串的值赋为x,操作2是找到所有是字符串t的子串的字符串的值的最大值。
题解
多串匹配问题很显然是个AC自动机问题,如果这题没有两个相同的串就几乎是一道模板题,只要在建trie时记录每个串对应的节点,修改时直接修改对应节点即可,查询时遍历后缀链接找出最大值即可。但如果有多个串相同,可能同一节点会有多个串与之对应,如果我们还是用val[ ]存储每个节点对应串的最大值,就要在每次修改中找到该点对应的所有串中的最大值(所以我们对每个节点建立一棵线段树)。我的做法是,对每个节点开一个pair型的优先队列,第一关键字存储数值,第二关键字存储对应字符编号,每次修改在对应节点加入pair(x,i),再根据该节点的优先队列值修改其val值。具体地,取出当前节点优先队列的首元素,如果首元素的i值已经不对应x值了,就pop出去,重复这一过程,否则x值为所有对应串的最大值。因为每次修改最多入队一次、出队一次,所以总修改时间复杂度为(O(Qlog Q))。而查询操作与普通AC自动机一样,于是总时间复杂度为(O(N+Qlog Q))
代码
/*************************************************************************
> File Name: 2.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https: https://www.cnblogs.com/Knowledge-Pig/
> Created Time: 2020/10/26 23:11:01
************************************************************************/
#include<bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define LL long long
#define pb push_back
#define fi first
#define se second
#define pr pair<int,int>
#define mk(a,b) make_pair(a,b)
using namespace std;
int read(){
char x=getchar(); int u=0,fg=0;
while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
return fg?-u:u;
}
const int maxx=1e6+10;
char s[maxx],t[maxx];
int n,m,pos[maxx],sp[maxx];
priority_queue<pr>que[maxx];
struct Trie{
int ch[maxx][30],val[maxx],f[maxx],last[maxx],sz;
Trie(){ sz=1; memset(ch[0],0,sizeof(ch[0])); }
int idx(char c){ return c-'a'; }
void insert(char *T,int id){
int u=0,len=strlen(T);
for(int i=0;i<len;++i){
int c=idx(T[i]);
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
val[sz]=-1;
ch[u][c]=sz++;
}
u=ch[u][c];
}
val[u]=0;
pos[id]=u;
que[u].push(pr(0,id));
}
void getfail(){
queue<int>q;
f[0]=0;
For(c,0,25){
int u=ch[0][c];
if(u){
q.push(u);
f[u]=0;
}
}
while(!q.empty()){
int r=q.front(); q.pop();
For(c,0,25){
int u=ch[r][c];
if(!u) ch[r][c]=ch[f[r]][c];
else{
q.push(u);
f[u]=ch[f[r]][c];
last[u]=(val[f[u]]>=0)?f[u]:last[f[u]];
}
}
}
}
int Find(char *T){
int len=strlen(T);
int j=0,ans=-1;
For(i,0,len-1){
int c=idx(T[i]);
j=ch[j][c];
for(int x=j;x;x=last[x]){
ans=max(val[x],ans);
}
}
return ans;
}
}trie;
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
n=read(); m=read();
For(i,1,n){
scanf("%s",t);
trie.insert(t,i);
}
trie.getfail();
while(m--){
int o=read();
if(o==1){
int u=read(),v=read(),z=pos[u];
sp[u]=v;
que[z].push(pr(v,u));
while(!que[z].empty()){
int x=que[z].top().fi,y=que[z].top().se;
if(sp[y]==x) break;
else que[z].pop();
}
trie.val[z]=que[z].top().fi;
}
else{
scanf("%s",t);
printf("%d
",trie.Find(t));
}
}
return 0;
}