题解 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;
}

posted @ 2022-07-27 21:47  Little09  阅读(35)  评论(0编辑  收藏  举报