CF1437G Death DBMS 题解
题目描述
给定 \(n\) 个字符串 \(s_i\) ,每个字符串有一个权值,初始为 \(0\) 。
接下来 \(m\) 次操作:
- 将第 \(k\) 个字符串的权值修改为 \(x\) 。
- 给定一个字符串 \(t\) ,求所有是 \(t\) 的子串的字符串 \(s_i\) 权值最大值,如果不存在则输出
-1。
数据范围
- \(1\le n,m\le 3\cdot 10^5\) 。
- \(0\le x\le 10^9,1\le \sum|s|,\sum|t|\le3\cdot10^5\) 。
分析
重工业数据结构,想题五分钟,写题两小时。
子串相关,果断建出 \(\texttt{AC}\) 自动机。
对于第一类操作,注意可能有重复的字符串,用 multiset 维护 \(\texttt{AC}\) 自动机上每个点的权值。
对于第二类操作,把 \(t\) 放在 \(\texttt{AC}\) 自动机上跑。每走一个字符,查询 \(fail\) 树上当前位置在 \(fail\) 树上到根的链中权值最大值,树剖线段树即可。
时间复杂度 \(\mathcal O((n+m+\sum|s|+\sum|t|)\log^2|s|)\) 。
天坑:常规写法中 \(fail\) 树下标从 \(0\) 开始,失配时会走到 \(0\) 号点(根节点),但是常规写法树剖初始化
son[u]=0以便后续更新。因此本题在求son[u]时需要特判son[u]=0的情形。如果你想下标平移也不是不行,但是会多很多细节并且像博主一样浪费好多时间。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
int m,n,cnt,tot;
int pos[maxn],val[maxn];
char s[maxn];
int fa[maxn],sz[maxn],son[maxn],dfn[maxn],top[maxn];
vector<int> g[maxn];
struct node
{
int ch[26],fail;
multiset<int> s;
}f[maxn];
void getfail()
{
queue<int> q;
for(int i=0;i<26;i++) if(f[0].ch[i]) q.push(f[0].ch[i]);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<26;i++)
if(f[u].ch[i]) f[f[u].ch[i]].fail=f[f[u].fail].ch[i],q.push(f[u].ch[i]);
else f[u].ch[i]=f[f[u].fail].ch[i];
}
}
void dfs1(int u)
{
sz[u]=1;
for(auto v:g[u])
{
fa[v]=u,dfs1(v),sz[u]+=sz[v];
if(!son[u]||sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int _f)
{
dfn[u]=++cnt,top[u]=_f;
if(son[u]) dfs2(son[u],_f);
for(auto v:g[u]) if(v!=son[u]) dfs2(v,v);
}
namespace sgmt
{
int p,mx[3*maxn];
void pushup(int p)
{
mx[p]=max(mx[p<<1],mx[p<<1|1]);
}
void init()
{
p=1<<(__lg(cnt)+1);
for(int i=p;i<=p+cnt+1;i++) mx[i]=-1;
for(int i=1;i<=n;i++) mx[p+dfn[pos[i]]]=0;
for(int i=p-1;i>=1;i--) pushup(i);
}
void modify(int x,int v)
{
x+=p,mx[x]=v;
for(;x!=1;x>>=1) pushup(x>>1);
}
int query(int l,int r)
{
int res=-1;
for(l=p+l-1,r=p+r+1;l^r^1;l>>=1,r>>=1)
{
if(~l&1) res=max(res,mx[l^1]);
if(r&1) res=max(res,mx[r^1]);
}
return res;
}
}
int query(int x)
{
int res=-1;
while(x) res=max(res,sgmt::query(dfn[top[x]],dfn[x])),x=fa[top[x]];
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,p=0;i<=n;i++)
{
scanf("%s",s+1),p=0;
for(int j=1,l=strlen(s+1);j<=l;j++)
{
int c=s[j]-'a';
if(!f[p].ch[c]) f[p].ch[c]=++tot;
p=f[p].ch[c];
}
pos[i]=p,f[p].s.insert(0);
}
getfail();
for(int i=1;i<=tot;i++) g[f[i].fail].push_back(i);
dfs1(0),dfs2(0,0),sgmt::init();
for(int op=0,x=0,y=0;m--;)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&x,&y);
auto &s=f[pos[x]].s;
s.erase(s.find(val[x])),s.insert(val[x]=y);
sgmt::modify(dfn[pos[x]],*--s.end());
}
else
{
scanf("%s",s+1),x=-1;
for(int i=1,l=strlen(s+1),p=0;i<=l;i++) p=f[p].ch[s[i]-'a'],x=max(x,query(p));
printf("%d\n",x);
}
}
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/16222278.html
浙公网安备 33010602011771号