题解 P8451 [LSOT-1] Crosspain
发现要支持可持久化。
众所周知,没有强制在线的可持久化等于没有可持久化。所以我们考虑离线,询问形成了一个树形结构,我们只要遍历这棵树,支持加入字符串、删除字符串、查询即可。
然后你会发现直接把 AC 自动机建出来就好了。具体地,先把所有要加入的串插到 trie 里去然后建 ACAM,每次加入、删除字符串等价于单点加、减;查询的时候在 ACAM 上走,每次到一个节点把它在 fail 树上到根的权值加一下。
这样你可以树剖。当然,它显然可以转化为子树加、减,单点查值。这样求一下 dfn,用树状数组就行了。
我这样写空间有点卡,找了一下似乎是 vector 开销比较大。
// Author: Little09
// Problem: P8451 [LSOT-1] Crosspain
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P8451
// Memory Limit: 192 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&(-x))
const int N=1e6+5,M=5e5+5;
int q;
char a[N];
int fa[M],b[M],ans[M];
vector<char>s[M];
vector<int>t[M];
namespace AC
{
int tr[N][26],tot=0;
int fail[N];
vector<int>g[N];
void insert(int id)
{
int u=0;
for (char i:s[id])
{
if (!tr[u][i-'a']) tr[u][i-'a']=++tot;
u=tr[u][i-'a'];
}
}
queue<int>q;
int dfn[N],cnt,siz[N];
void dfs(int x)
{
dfn[x]=++cnt,siz[x]=1;
for (int i:g[x])
{
dfs(i);
siz[x]+=siz[i];
}
}
int tree[N];
inline void add(int x,int k)
{
for (;x<=cnt;x+=lowbit(x)) tree[x]+=k;
}
inline void update(int id,int k)
{
int u=0;
for (char i:s[id]) u=tr[u][i-'a'];
add(dfn[u],k);
add(dfn[u]+siz[u],-k);
}
inline int ask(int id)
{
int u=0,ans=0;
for (char i:s[id])
{
u=tr[u][i-'a'];
int x=dfn[u];
for (;x;x-=lowbit(x)) ans+=tree[x];
}
return ans;
}
void build()
{
for (int i=0;i<26;i++)
{
if (tr[0][i]) q.push(tr[0][i]);
}
while (!q.empty())
{
int u=q.front();
q.pop();
for (int i=0;i<26;i++)
{
if (tr[u][i])
{
fail[tr[u][i]]=tr[fail[u]][i];
q.push(tr[u][i]);
}
else tr[u][i]=tr[fail[u]][i];
}
}
for (int i=1;i<=tot;i++) g[fail[i]].push_back(i);
dfs(0);
}
}
inline int read()
{
int F=1,ANS=0;
char C=getchar();
while (C<'0'||C>'9')
{
if (C=='-') F=-1;
C=getchar();
}
while (C>='0'&&C<='9')
{
ANS=ANS*10+C-'0';
C=getchar();
}
return F*ANS;
}
void dfs(int x)
{
if (b[x]==1) AC::update(x,1);
if (b[x]==2) ans[x]=AC::ask(x);
for (int i:t[x]) dfs(i);
if (b[x]==1) AC::update(x,-1);
}
int main()
{
q=read();
for (int i=1;i<=q;i++)
{
b[i]=read(),fa[i]=read();
t[fa[i]].push_back(i);
scanf("%s",a);
int l=strlen(a);
for (int j=0;j<l;j++) s[i].push_back(a[j]);
if (b[i]==1) AC::insert(i);
}
AC::build();
dfs(0);
for (int i=1;i<=q;i++)
{
if (b[i]==2) printf("%d\n",ans[i]);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构