BZOJ 4231 回忆树(AC自动机+BIT+KMP)

本文介绍了一种名为回忆树的数据结构,它是一个无向连通图,每个边都有一个字符。在给定起点u、终点v和字符串s的情况下,需要找出从u到v路径上字符串s出现的次数。这个问题通过将s的出现分为3类,并利用KMP算法和AC自动机进行求解。在DFS过程中维护AC自动机的状态和贡献。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回忆树是树。
具体来说,是n个点n-1条边的无向连通图,点标号为1~n,每条边上有一个字符(出于简化目的,我们认为只有小写字母)。
对一棵回忆树来说,回忆当然是少不了的。
一次回忆是这样的:你想起过往,触及心底…唔,不对,我们要说题目。
这题中我们认为回忆是这样的:给定2个点u,v(u可能等于v)和一个非空字符串s,问从u到v的简单路径上的所有边按照到u的距离从小到大的顺序排列后,边上的字符依次拼接形成的字符串中给定的串s出现了多少次。
对于100100%%%100%的数据,n&lt;=100000,m&lt;=100000n&lt;=100000,m&lt;=100000n<=100000,m<=100000,询问串的总长&lt;=300000&lt;=300000<=300000

我们把s的在u−&gt;vu-&gt;vu>v中的出现拆分成3个类。
1:包含lca,那么只有从lca往u,v走∣S∣|S|S条边内的所有点可能被涉及,直接跑KMP。
2:uuu为起点往上的链。
3:vvv为终点往下的链。
那么后两者都可以用一条树链上的字符串在AC自动机上的贡献-字符串选有字符在lca以上的贡献得到。
在dfs的时候维护字符串在AC自动机上的位置和贡献就行。

AC Code:

#include<bits/stdc++.h>
#define maxn 600005
#define maxc 26
using namespace std;

int n,m,ans[maxn],loc[maxn];

int st[maxn],ed[maxn];
namespace AC{
   
   	
	int tr[maxn][maxc],tot;
	vector<int>G[maxn];
	int fa[maxn],id[maxn],dfn;
	
	void insert(char *s,int id){
   
   
		int u = 0;
		for(int i=0,len = strlen(s);i<len;u=tr[u][s[i]-'a'],i++)
			if(!tr[u][s[i]-'a']) tr[u][s[i]-'a'] = ++tot;
		loc[id] = u;
	}
	
	void dfs(int now){
   
   
		st[now] = ++dfn;
		for(int i=0,sz=G[now].size(),v;i<sz;i++)
			dfs(v=G[now][i]);
		ed[now] = dfn;
	}
	
	void Build(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值