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之模块与包

    模块介绍 一个模块就是包含了一组功能的python文件(例如module.py,模块名是module),它从文件级别组织程序,更方便管理,这时我们不仅仅可以把这些文件当作脚本执行,还可以把他们当作模块 ...

  2. java导出html页面

    http://blog.csdn.net/zhyh1986/article/details/8727523#t6 http://blog.csdn.net/zuozuofuwaiwai/article ...

  3. CF1012B Chemical table 构造_思维_并查集

    我们可以将横坐标和纵坐标看成是点.发现这些点之间是有传递性的. 题中说明,如果有矩阵中三个顶点被选,则底角的点也会被覆盖,发现这些点之间是有传递性的.那么我们最终达到的目的就是使整个图中只有 111 ...

  4. .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)

    最近在项目中与别的公司对接业务,对方是Java语言,需要调用对方的WebServices,结果常规的添加web引用的方法可以传过去值,但是返回值为null 查了很多资料,没有解决方法 思考应该是.Ne ...

  5. 使用Oracle Database Instant Client 精简版

    如果只为了在开发环境中访问Oracle,推荐使用Oracle Database Instant Client(精简版)它相对小巧且不需要安装绿色方便移植. 官方下载Instant Client,在Or ...

  6. Null值操作

      1)NULL值写入的操作    create table j010(     id number(7),     name varchar2(20),     salary number(7,2) ...

  7. Springboot 应用启动分析

    https://blog.csdn.net/hengyunabc/article/details/50120001#comments 一,spring boot quick start 在spring ...

  8. UltraEdit正則表達式介绍及实例

    前几天,有个将Excel中的数据导入到数据库中的需求.原本想到用程序读取Excel中的数据并存储到数据库中,但经一哥们的提醒,说用 EditPlus或UltraEdit这种工具直接将数据拼凑成SQL插 ...

  9. php抽奖、随机广告算法

    我们先完毕后台PHP的流程,PHP的主要工作是负责配置奖项及相应的中奖概率,当前端页面点击翻动某个方块时会想后台PHP发送ajax请求,那么后台PHP依据配置的概率,通过概率算法给出中奖结果,同一时候 ...

  10. WPF错误:必须使“Property”具有非 null 值。

    这个问题一般出如今Triggers中Property指定的类型为Nullable. 解决的方法就是用DataTrigger取代Trigger, 然后用Binding+Converter转换为详细非Nu ...