BZOJ3413: 匹配(后缀自动机,Parent树,线段树合并)
Description
.jpg)
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
1090901
4
87650
0901
109
090
Sample Output
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树,线段树合并)的更多相关文章
- [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)
		
题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...
 - 【codeforces666E】Forensic Examination  广义后缀自动机+树上倍增+线段树合并
		
题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r ...
 - BZOJ3413: 匹配(后缀自动机 线段树合并)
		
题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...
 - CF1037H Security 后缀自动机 + right集合线段树合并 + 贪心
		
题目描述: 给定一个字符串 $S$ 给出 $Q$ 个操作,给出 $L,R,T$,求出字典序最小的 $S_{1}$ 为 $S[L...R]$的子串,且 $S_{1}$ 的字典序严格大于 $T$. 输出这 ...
 - CF700E Cool Slogans 后缀自动机 + right集合线段树合并 + 树形DP
		
题目描述 给出一个长度为n的字符串s[1],由小写字母组成.定义一个字符串序列s[1....k],满足性质:s[i]在s[i-1] (i>=2)中出现至少两次(位置可重叠),问最大的k是多少,使 ...
 - 浅谈树套树(线段树套平衡树)&学习笔记
		
0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...
 - BZOJ 3413 匹配 (后缀自动机+线段树合并)
		
题目大意: 懒得概括了 神题,搞了2个半晚上,还认为自己的是对的...一直调不过,最后终于在jdr神犇的帮助下过了这道题 线段树合并该是这道题最好理解且最好写的做法了,貌似主席树也行?但线段树合并这个 ...
 - [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
		
题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...
 - Luogu3732 [HAOI2017] 供给侧改革 【后缀数组】【线段树】【乱搞】
		
题目分析: 这道题我是乱搞的,因为他说$01$串是随机的. 那么我们可以猜测能够让LCP变大的地方很少.求出后缀数组之后可能让LCP变大的地方就等价于从大到小往height里动态加点同时维护这个点左右 ...
 - Luogu5289 十二省联考2019字符串问题(后缀数组+拓扑排序+线段树/主席树/KDTree)
		
先考虑80分做法,即满足A串长度均不小于B串,容易发现每个B串对应的所有A串在后缀数组上都是一段连续区间,线段树优化连边然后判环求最长链即可.场上就写了这个. 100分也没有什么本质区别,没有A串长度 ...
 
随机推荐
- 算法23-------岛屿的最大面积 LeetCode 695
			
一.题目: 给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合.你可以假设二维矩阵的四个边缘都被水包围着. 找到给定 ...
 - Python数据分析8-----网页文本处理
			
1.去除网页的标签,如<br/> from bs4 import BeautifulrSoup preData=BeautifulSoup(data,'html.parser').get_ ...
 - 02 C#高级
			
第九天 面向过程--à面向对象 面向过程:面向的是完成这件事儿的过程,强调的是完成这件事儿的动作. 把大象塞进冰箱 1. 打开冰箱门 2. 把大象塞进去,亲下大象的屁股 3. 关闭冰箱门 孙全 瘦小 ...
 - [NOIP补坑计划]NOIP2017 题解&做题心得
			
终于做完了…… 场上预计得分:?(省一分数线:295) 由于看过部分题解所以没有预计得分qwq 题解: D1T1 小凯的疑惑 题面 震惊!一道小学奥数题竟难倒无数高中考生! 欢迎大家以各种姿势*和谐* ...
 - [BOI2011]MET-Meteors
			
题目:洛谷P3527. 题目大意:n个国家在某星球上建立了m个空间站(一个空间站只属于一个国家),空间站围成一个环.现在知道要下k天陨石,每天都在一个区间内下,每个点都下同样多的(若r>l,则说 ...
 - webstorm注册码注册
			
最近jetbrains公司更新软件总是特别的快,很多私人搭建的server服务也失效了,现出一个能够永久破解的方法,非常简单,只需要2步就完成. 第一步 复制下方activation code,直接粘 ...
 - invalid application of `sizeof' to incomplete type `char[] '
			
在写代码时,我想用extern来关联一个数组,然后利用sizeof计算数组的大小,代码如下: ... extern char a[]; #define b size=(sizeof(a)/sizeof ...
 - js实现点击复制网页内容(基于clipboard.js)
			
浏览网页过程中会遇到点击复制链接地址的情况,下面就介绍一种实现方法,该方法是基于clipboard.js: 官网地址:https://clipboardjs.com/: clipboard.js使用比 ...
 - 表单标签 fieldset legent
			
书写表单时可以提供简单样式的标签 <fieldset> <legent></legent> <input type="text" > ...
 - ASP.NET-DropDownListFor绑定model数据
			
在ASP.NET中,DropDownListFor绑定model数据比用html的select方便太多了,配合listmode这种模型集合就可以在controller里面直接foreach循环处理li ...