字典树,扫描线+线段树
题意
给n个原串,q个查询,每个查询给出一个前缀和后缀,问原串中有多少个串的前缀和后缀满足该查询
- n,q<=100000
- ∑Si+Pi≤500000,∑Wi≤500000
题解
- 假设原始的字符串 数组为A,首先将A中的每个字符串都进行翻转,得到字符串数组B,然后,将A和B按字典序排序。
- 对于一个查询来说有一个前缀p和后缀s, 所有包含前缀p的字符串在A中是连续的,可通过二分求出该区间 设为[Lp,Rp],同样,所有包含后缀s的字符串在B中也是连续的,设为[Ls,Rs]
- 接下来只需求解 有多少个字符串前缀是在[Lp,Rp] 同时后缀在[Ls,Rs]。对于每个字符串,假设在A中是第x个,在B中是第y个 ,那么我们只需要判断有多少个字符串 Lp<=x<=Rp 同时 Ls<=y<=Rs
- 该问题转化为,有一些点(每个字符串相当于一个点,x是按前缀排完序的位置,y是按后缀排序),现给定一些矩形(每个查询可转化为 Lp<=x<=Rp,Ls<=y<=Rs),问矩形中包含多少个点,该问题是经典的矩形覆盖问题,线段树+扫描线 即可求出。
- 按上述方法求出后,会存在重叠的问题 。如有一个字符串 aaa 查询如果为 aa aa的话也会查到 aaa。 那么我们需要进行去重,可直接对查询的前缀或者后缀做一个遍历,枚举重叠的长度,然后再哈希判断是否存在这样的原始字符串即可。
- 时间复杂度O(nlog(n)+∣S∣)
- 避免hash可以离线暴力在字典树上建线段树,查询在字典树上找到后缀对应节点查找前缀区间和。空间O(∣S∣log(n))。时间复杂度O(nlog(n)+∣S∣)
- 也可以直接hash离线做。
代码
|
|