Description

Input

第一行包含一个整数n(≤100000)。

第二行是长度为n的由0到9组成的字符串。

第三行是一个整数m。

接下来m≤5·10行,第i行是一个由0到9组成的字符串s,保证单行字符串长度小于等于10^5,所有字符串长度和小于等于3·10^6

Output

输出m行,第i行表示第si和S匹配所比较的次数。

Sample Input

7
1090901
4
87650
0901
109
090

Sample Output

7
10
3
4

解题思路:

卡了我一天,我好弱啊

这道题需要在思路上做出一步转化,将分配次数分配到每个点上。

话句话说,假如说在模板串i位上匹配了f[i]次,那么答案就是sigma(f[i])。

那么就要求我们求出在每一位上的f[i]的值。

f[i]=在i上失配次数+在i上匹配成功次数,其中失配次数可以单独处理出来。

如果匹配永远不会成功,那么,我们可以知道,失配次数一定是n。

如果匹配在某一位成功,那么失配次数就是左端点右移次数。

那么成功次数呢?

可知,在完成匹配之后的部分,是不产生贡献的。

那么结果就是在一个Parent节点子树内的结束节点。

所以我们就需要维护一个集合,集合内包含所有Parent节点子树内的endpos。

这部分用线段树就好了,向上合并。

查询个数时只需要确定好上限。

查询结束位置时只需要进行后缀自动机匹配即可,记录最后一个节点并保证未失配。

再进行第二次匹配,只需要限制其上限,在线段树中查询个数就好了。

代码:

 #include<cstdio>
#include<cstring>
#include<algorithm>
const int N=;
const int S=;
typedef long long lnt;
struct sant{
int tranc[];
int len;
int pre;
}s[S];
struct pnt{
int hd;
int root;
}p[S];
struct trnt{
int ls;
int rs;
int sum;
}tr[S<<];
int cnt;
int siz;
int fin;
int n,Q;
int top;
int size;
char tmp[N];
int topo[S];
int has[S];
int t;
void pushup(int spc)
{
tr[spc].sum=tr[tr[spc].ls].sum+tr[tr[spc].rs].sum;
return ;
}
int hav(int l,int r,int spc,int pos)
{
if(!spc)
return ;
if(l==r)
return l;
int mid=(l+r)>>;
if(pos<=mid)
return hav(l,mid,tr[spc].ls,pos);
else
return hav(mid+,r,tr[spc].rs,pos);
}
void update(int l,int r,int &spc,int pos)
{ if(!spc)
spc=++size;
tr[spc].sum++;
if(l==r)
return ;
int mid=(l+r)>>;
if(pos<=mid)
update(l,mid,tr[spc].ls,pos);
else
update(mid+,r,tr[spc].rs,pos);
return ;
}
int Merge(int spcf,int spcs)
{
if(!spcf||!spcs)
return spcf+spcs;
int spc=++size;
tr[spc].sum=tr[spcf].sum+tr[spcs].sum;
tr[spc].ls=Merge(tr[spcf].ls,tr[spcs].ls);
tr[spc].rs=Merge(tr[spcf].rs,tr[spcs].rs);
return spc;
}
int Minpos(int l,int r,int spc)
{
if(l==r)
return l;
int mid=(l+r)>>;
if(tr[tr[spc].ls].sum)
return Minpos(l,mid,tr[spc].ls);
else
return Minpos(mid+,r,tr[spc].rs);
}
lnt query(int l,int r,int spc,int lim)
{
if(l>lim||!spc)
return ;
if(l==r||r<=lim)
return tr[spc].sum;
int mid=(l+r)>>;
return query(l,mid,tr[spc].ls,lim)+query(mid+,r,tr[spc].rs,lim);
}
void Insert(int c,int plc)
{
t=plc;
int nwp,nwq,lsp,lsq;
nwp=++siz;
s[nwp].len=s[fin].len+;
for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)
s[lsp].tranc[c]=nwp;
if(!lsp)
s[nwp].pre=;
else{
lsq=s[lsp].tranc[c];
if(s[lsq].len==s[lsp].len+)
s[nwp].pre=lsq;
else{
nwq=++siz;
s[nwq]=s[lsq];
s[nwq].len=s[lsp].len+;
s[lsq].pre=s[nwp].pre=nwq;
while(s[lsp].tranc[c]==lsq)
{
s[lsp].tranc[c]=nwq;
lsp=s[lsp].pre;
}
}
}
fin=nwp;
update(,n,p[fin].root,plc);
return ;
}
int main()
{
fin=++siz;
scanf("%d",&n);
scanf("%s",tmp+);
for(int i=;i<=n;i++)
Insert(tmp[i]-'',i);
for(int i=;i<=siz;i++)
has[s[i].len]++;
for(int i=;i<=siz;i++)
has[i]+=has[i-];
for(int i=;i<=siz;i++)
topo[has[s[i].len]--]=i;
for(int i=siz;i;i--)
{
int x=topo[i];
if(x==)
continue;
p[s[x].pre].root=Merge(p[s[x].pre].root,p[x].root);
}
scanf("%d",&Q);
while(Q--)
{
scanf("%s",tmp+);
int len=strlen(tmp+);
int root=;
int endpos=0x3f3f3f3f;
lnt ans=;
for(int i=;i<=len;i++)
root=s[root].tranc[tmp[i]-''];
if(!root)
ans=n;
else{
endpos=Minpos(,n,p[root].root);
ans=endpos-len;
}
root=;
for(int i=;i<=len;i++)
{
int c=tmp[i]-'';
root=s[root].tranc[c];
int tmp=ans;
if(root)
ans+=query(,n,p[root].root,endpos+i-len);
else
break;
}
printf("%lld\n",ans);
}
return ;
}

BZOJ3413: 匹配(后缀自动机,Parent树,线段树合并)的更多相关文章

  1. [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)

    题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...

  2. 【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并

    题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r ...

  3. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

  4. CF1037H Security 后缀自动机 + right集合线段树合并 + 贪心

    题目描述: 给定一个字符串 $S$ 给出 $Q$ 个操作,给出 $L,R,T$,求出字典序最小的 $S_{1}$ 为 $S[L...R]$的子串,且 $S_{1}$ 的字典序严格大于 $T$. 输出这 ...

  5. CF700E Cool Slogans 后缀自动机 + right集合线段树合并 + 树形DP

    题目描述 给出一个长度为n的字符串s[1],由小写字母组成.定义一个字符串序列s[1....k],满足性质:s[i]在s[i-1] (i>=2)中出现至少两次(位置可重叠),问最大的k是多少,使 ...

  6. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  7. BZOJ 3413 匹配 (后缀自动机+线段树合并)

    题目大意: 懒得概括了 神题,搞了2个半晚上,还认为自己的是对的...一直调不过,最后终于在jdr神犇的帮助下过了这道题 线段树合并该是这道题最好理解且最好写的做法了,貌似主席树也行?但线段树合并这个 ...

  8. [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增

    题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...

  9. Luogu3732 [HAOI2017] 供给侧改革 【后缀数组】【线段树】【乱搞】

    题目分析: 这道题我是乱搞的,因为他说$01$串是随机的. 那么我们可以猜测能够让LCP变大的地方很少.求出后缀数组之后可能让LCP变大的地方就等价于从大到小往height里动态加点同时维护这个点左右 ...

  10. Luogu5289 十二省联考2019字符串问题(后缀数组+拓扑排序+线段树/主席树/KDTree)

    先考虑80分做法,即满足A串长度均不小于B串,容易发现每个B串对应的所有A串在后缀数组上都是一段连续区间,线段树优化连边然后判环求最长链即可.场上就写了这个. 100分也没有什么本质区别,没有A串长度 ...

随机推荐

  1. Python-ORM实战

    Date: 2019-06-03 Author: Sun 什么是ORM? ​ ORM(object relational mapping), 就是对象关系映射,简单来说我们类似python这种面向对象 ...

  2. Pyhton学习——Day54

    #Django内容回顾# -请求响应HTTP协议(有.无状态)默认传递的是字符串# 传递字符串分为两个部分:1.http1.1 GET /url /index + 请求头# Provisional h ...

  3. 【BZOJ1396】识别子串 - 后缀自动机+线段树

    题意: Description Input 一行,一个由小写字母组成的字符串S,长度不超过10^5 Output L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长. 题解: ...

  4. JS中的与冒号的作用、箭头函数相关的一道题

    相关知识来自于一道题: 使用ES6的箭头函数语法可以直接省略 function 和 return 关键字,比如 function (){return 1;} 就可以简化成 () => 1 , 但 ...

  5. 关于Number的属性和方法你知晓几分?速来围观!

    1.Number.isFinite() 方法用来检测传入的参数是否是一个有穷数(finite number)返回值为布尔值. 和全局的 isFinite() 函数相比,这个方法不会强制将一个非数值的参 ...

  6. 四则运算2(最终版)java+jps+sqlServer

    1,设计思想 (1)在java Resources里建立包和类 (2)在类里面写入方法,其中包括生成算式create()和删除算式delete()用来更新数据库中的题目 (3)Show()方法用来随机 ...

  7. 单元测试Struts2Spring项目的Action和Service(包含源码)

    最近,认真实践了单元测试Struts2.Spring等Java项目,今天特意写的是单元测试Struts2Spring项目的Action和Service. 由于已经写过不少Web开发框架单元测试的代码, ...

  8. shell 键盘录入和运算

    一.read 命令,从键盘读入数据,赋给变量 1.脚本代码 #!/bin/sh read arg1 arg2 echo "第一个参数: $arg1" echo "第二个参 ...

  9. Bridge桥接模式(设计模式11)

    在没有使用桥接模式: 扩展新问题(类归属膨胀问题) 1增加性的电脑类型,要增加每个品牌下面的类 2如果要增加一个新的电脑品牌,要增加美中电脑类型的类 违背单一职责原则: · 一个类:联想笔记本,有两个 ...

  10. POJ 1942

    开始时竟然用了分情况讨论. 仔细思考一下,哈哈,发现不过是多重集合的组合数而已. #include <iostream> #include <cstdio> #include ...