题意:
给定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.
code:
#include<bits/stdc++.h>
using 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<int>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<int>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;
}