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串长度 ...
随机推荐
- flex-2
1. 2. justify:整理版面 3. 4.归纳 justify-content:flex-start(默认).center.flex-end 下面还会提到剩下的两种项目在主轴上对齐方式: spa ...
- java 公开内部类无法实例化 no enclosing instance 解决办法
因为B类不是A类的静态内部类,所以B累也只能像A类的成员一样通过new A()的实例访问,new(new A()).B(),这显然不是我们想要的方式,于是需要在B类的前边加上static,变成下边这样 ...
- freeswitch GUI界面(portal)
1.控制台 加载模块 load mod_xml_rpc 2.ip:8080/portal 进行登录 账号 : freeswitch 密码 : works 让模块随着freeswitch启动进行加载 ...
- 小记如何有顺序的搭建一个Spring的web项目
如何有顺序的搭建一个Spring的web项目 一.新建一个简单的maven,war工程 eclipse下如有报错,右键 Deployment 单击 Generate 生成web.xml后可解决报错 二 ...
- VUE:项目的创建、编写、打包及规范检查
VUE:项目的创建.编写及打包 项目的创建 使用 vue-cli 创建模板项目(官方提供的脚手架工具) https://github.com/vuejs/vue-cli npm install -g ...
- RabbitMQ学习总结(6)——消息的路由分发机制详解
一.Routing(路由) (using the Java client) 在前面的学习中,构建了一个简单的日志记录系统,能够广播所有的日志给多个接收者,在该部分学习中,将添加一个新的特点,就是可以只 ...
- 聚类算法学习-kmeans,kmedoids,GMM
GMM参考这篇文章:Link 简单地说,k-means 的结果是每个数据点被 assign 到其中某一个 cluster 了,而 GMM 则给出这些数据点被 assign 到每个 cluster 的概 ...
- 【转载】Select函数实现原理分析
Select函数实现原理分析 <原文> select需要驱动程序的支持,驱动程序实现fops内的poll函数.select通过每个设备文件对应的poll函数提供的信息判断当前是否有资源可用 ...
- HDU 5228 ZCC loves straight flush( BestCoder Round #41)
题目链接:pid=5228">ZCC loves straight flush pid=5228">题面: pid=5228"> ZCC loves s ...
- phonegap(cordova) 自己定义插件代码篇(六)----android ,iOS 微信支付工具整合
还是那句话,在使用插件代码篇的时候,请先了解插件机制(如整合原生插件先阅读原生插件文档.非常重要.非常重要!非常重要!),如未了解,请先阅读入门篇.这里就专贴关键代码 必须先把官方sdk 依照要求一步 ...