本文共 2313 字,大约阅读时间需要 7 分钟。
给定n个串si,一开始每个串的权值为0,
m次操作,操作有两种: (1 i x):将第i个串的权值设为x, (2 q):给定串q,在n个串中找到一个最大权值的串,满足这个串是q的子串,输出最大权值,如果不存在子串,那么输出-1。数据范围:n,m<=3e5,sum(|si|),sum(|q|)<=3e5
对n个串建AC自动机,每个节点开一个multiset维护最大值,修改操作直接修改multiset中的元素,查询操作就暴力跳last,对经过的节点的multiset的取max.
#includeusing namespace std;const int maxm=3e5+5;char s[maxm];int n,m;struct AC{ int a[maxm][26]; int ed_pos[maxm]; int val[maxm]; int fail[maxm]; int last[maxm]; int tot; multiset ss[maxm]; void add(char *s,int idx){ int node=0; for(int i=0;s[i];i++){ int v=s[i]-'a'; if(!a[node][v])a[node][v]=++tot; node=a[node][v]; } ed_pos[idx]=node; val[idx]=0;//这里必须val[idx],不能val[node],因为node会重复 ss[node].insert(val[idx]); } void build(){ for(int i=0;i<=tot;i++){ ss[i].insert(-1); } queue q; for(int i=0;i<26;i++){ if(a[0][i]){ fail[a[0][i]]=0; q.push(a[0][i]); } } while(!q.empty()){ int x=q.front();q.pop(); last[x]=*ss[fail[x]].rbegin()>=0?fail[x]:last[fail[x]]; for(int i=0;i<26;i++){ if(a[x][i]){ fail[a[x][i]]=a[fail[x]][i]; q.push(a[x][i]); }else{ a[x][i]=a[fail[x]][i]; } } } } void update(int idx,int x){ int pos=ed_pos[idx]; ss[pos].erase(ss[pos].find(val[idx])); val[idx]=x; ss[pos].insert(val[idx]); } int ask(char *s){ int ans=-1; int node=0; for(int i=0;s[i];i++){ int v=s[i]-'a'; node=a[node][v]; for(int t=node;t;t=last[t]){ ans=max(ans,*ss[t].rbegin()); } } return ans; }}ac;signed main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%s",s); ac.add(s,i); } ac.build(); while(m--){ int op;scanf("%d",&op); if(op==1){ int i,x;scanf("%d%d",&i,&x); ac.update(i,x); }else{ scanf("%s",s); int ans=ac.ask(s); printf("%d\n",ans); } } return 0;}
转载地址:http://hskv.baihongyu.com/