BZOJ 4231 回忆树(KMP+AC自动机+fail树+树状数组)

题目

Description

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

Input

第一行2个整数,依次为树中点的个数n和回忆的次数m。
接下来n-1行,每行2个整数u、v和1个小写字母c,表示回忆树的点u、v之间有一条边,边上的字符为c
接下来2m行表示m次回忆,每次回忆2行:第1行2个整数u、v,第2行给出回忆的字符串s。

Output

对于每次回忆,输出串s出现的次数。

Sample Input

12 3
1 2 w
2 3 w
3 4 x
4 5 w
5 6 w
6 7 x
7 8 w
8 9 w
9 10 x
10 11 w
11 12 w
1 7
wwx
1 12
www
1 12

Sample Output

2
0
8

HINT

对于100%的数据,n<=100000,m<=100000,询问串的总长<=300000

Time Limit: 10 Sec Memory Limit: 256 MB

题解

将每条路径分为向上的路径和向下的路径,则字符串s出现的情况有两种,分情况讨论

1.s经过了LCA(u,v):此时字符串长度不超过2|s|,用KMP进行比较
2.s只存在一条路径上:将所有s的正串和反串分别建立AC自动机,DFS原树,经过一个节点时,在AC自动机上对应的节点处+1,遍历完子树后-1,答案即为fail树上s对应的的子树权值和

求出fail树的DFS序,用树状数组维护子树权值

时间复杂度: O((n+m)logn+|s|) O ( ( n + m ) l o g n + ∑ | s | )

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#define LL long long
using namespace std;
const int maxn=100005,maxs=600005,SIZE=26;
int n,m,sums=1,cc,ccc,x,y,z,zz;
char
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值