CF1437G Death DBMS 题解
目录
题目描述
给定 个字符串 ,每个字符串有一个权值,初始为 。
接下来 次操作:
- 将第 个字符串的权值修改为 。
- 给定一个字符串 ,求所有是 的子串的字符串 权值最大值,如果不存在则输出
-1
。
数据范围
- 。
- 。
分析
重工业数据结构,想题五分钟,写题两小时。
子串相关,果断建出 自动机。
对于第一类操作,注意可能有重复的字符串,用 multiset
维护 自动机上每个点的权值。
对于第二类操作,把 放在 自动机上跑。每走一个字符,查询 树上当前位置在 树上到根的链中权值最大值,树剖线段树即可。
时间复杂度 。
天坑:常规写法中 树下标从 开始,失配时会走到 号点(根节点),但是常规写法树剖初始化
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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?