FDUSC前刷刷题吧。。

本题每个询问就是说将询问串与主串每个后缀匹配,若匹配成功则结束,否则加上lcp的长度

对主串建立后缀树,并用主席树维护DFS序

对于每个询问串,找到最后走到的点fin_node(在边上就往下走),

并求出完成匹配的后缀的位置match(若匹配成功则是fin_node子树中的最小值,否则就是n)

然后从fin_node开始一直往上走,

每个节点对答案的贡献为该点子树中小于等于match的后缀的个数乘以这条边的长度,

答案最后再加上match

时间复杂度预处理$O(n\log n)$,询问$O(m\log n)$

#include<cstdio>
#include<cstring>
const int inf=1<<25,S=12,N=100010,M=1800010;
using namespace std;
char tmp[N];
int text[N],root,last,pos,need,remain,acnode,ace,aclen;
int n,m,i,fin_node,fin_len,match,ans;
int dfn,seq[N<<1],st[N<<1],en[N<<1];
int head[N<<1],tot,val[M],l[M],r[M];
int min(int a,int b){return a<b?a:b;}
struct node{int st,en,lk,son[S],f;int len(){return min(en,pos+1)-st;}}tree[N<<1];
int new_node(int st,int en=inf){
node nd;
nd.st=st;nd.en=en;
for(int i=nd.lk=0;i<S;i++)nd.son[i]=0;
tree[++last]=nd;
return last;
}
int acedge(){return text[ace];}
void addedge(int node){
if(need)tree[need].lk=node;
need=node;
}
bool down(int node){
if(aclen>=tree[node].len())return ace+=tree[node].len(),aclen-=tree[node].len(),acnode=node,1;
return 0;
}
void init(){
need=last=remain=ace=aclen=0;
root=acnode=new_node(pos=-1,-1);
}
void extend(int c){
text[++pos]=c;need=0;remain++;
while(remain){
if(!aclen)ace=pos;
if(!tree[acnode].son[acedge()])tree[acnode].son[acedge()]=new_node(pos),addedge(acnode);
else{
int nxt=tree[acnode].son[acedge()];
if(down(nxt))continue;
if(text[tree[nxt].st+aclen]==c){aclen++;addedge(acnode);break;}
int split=new_node(tree[nxt].st,tree[nxt].st+aclen);
tree[acnode].son[acedge()]=split;
tree[split].son[c]=new_node(pos);
tree[nxt].st+=aclen;
tree[split].son[text[tree[nxt].st]]=nxt;
addedge(split);
}
remain--;
if(acnode==root&&aclen)aclen--,ace=pos-remain+1;
else acnode=tree[acnode].lk?tree[acnode].lk:root;
}
}
bool search(){
int x=fin_node=root,i=1,j;
fin_len=0;
while(i<=n){
if(tree[x].son[tmp[i]-'0'+1]){
x=fin_node=tree[x].son[tmp[i]-'0'+1];
fin_len=0;
j=tree[x].st;
while(i<=n&&j<min(tree[x].en,pos+1))if(tmp[i]-'0'+1==text[j])i++,j++,fin_len++;else return 0;
}else return 0;
}
return 1;
}
void dfs(int x,int sum,int f){
tree[x].f=f;
sum+=tree[x].len();
seq[st[x]=++dfn]=tree[x].en==inf?pos-sum+1:-1;
for(int i=0;i<S;i++)if(tree[x].son[i])dfs(tree[x].son[i],sum,x);
en[x]=dfn;
}
int ins(int x,int a,int b,int c){
int y=++tot;
val[y]=val[x]+1;
if(a==b)return y;
int mid=(a+b)>>1;
if(c<=mid)l[y]=ins(l[x],a,mid,c),r[y]=r[x];else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c);
return y;
}
int ask(int x,int a,int b,int c){
if(!x)return 0;
if(b<=c)return val[x];
int mid=(a+b)>>1,t=ask(l[x],a,mid,c);
if(c>mid)t+=ask(r[x],mid+1,b,c);
return t;
}
int askmin(int x,int y){
int a=0,b=pos,mid;
while(1){
if(a==b)return a;
mid=(a+b)>>1;
if(val[l[y]]>val[l[x]])x=l[x],y=l[y],b=mid;else x=r[x],y=r[y],a=mid+1;
}
}
int main(){
init();
scanf("%d%s",&n,tmp+1);
for(i=1;i<=n;i++)extend(tmp[i]-'0'+1);extend(11);
dfs(root,0,0);
for(i=1;i<=dfn;i++)head[i]=~seq[i]?ins(head[i-1],0,pos,seq[i]):head[i-1];
scanf("%d",&m);
while(m--){
scanf("%s",tmp+1);n=strlen(tmp+1);
ans=match=search()?askmin(head[st[fin_node]-1],head[en[fin_node]]):pos;
if(fin_node!=root){
ans+=fin_len*(ask(head[en[fin_node]],0,pos,match)-ask(head[st[fin_node]-1],0,pos,match));
fin_node=tree[fin_node].f;
}
while(fin_node!=root){
ans+=tree[fin_node].len()*(ask(head[en[fin_node]],0,pos,match)-ask(head[st[fin_node]-1],0,pos,match));
fin_node=tree[fin_node].f;
}
printf("%d\n",ans);
}
return 0;
}

  

BZOJ3413 : 匹配的更多相关文章

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

    Description Input 第一行包含一个整数n(≤100000). 第二行是长度为n的由0到9组成的字符串. 第三行是一个整数m. 接下来m≤5·10行,第i行是一个由0到9组成的字符串s, ...

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

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

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

    [BZOJ3413]匹配(后缀自动机,线段树合并) 题面 BZOJ 题解 很好的一道题目. 做一个转化,匹配的次数显然就是在可以匹配的区间中,每个前缀的出现次数之和. 首先是空前缀的出现次数,意味着你 ...

  4. 【BZOJ3413】匹配 离线+后缀树+树状数组

    [BZOJ3413]匹配 Description Input 第一行包含一个整数n(≤100000). 第二行是长度为n的由0到9组成的字符串. 第三行是一个整数m. 接下来m≤5·10行,第i行是一 ...

  5. javascript匹配各种括号书写是否正确

    今天在codewars上做了一道题,如下 看上去就是验证三种括号各种嵌套是否正确书写,本来一头雾水,一种括号很容易判断, 但是三种怎么判断! 本人只是个前端菜鸟,,不会什么高深的正则之类的. 于是,在 ...

  6. scanf类型不匹配造成死循环

        int i = 0; while (flag) { printf("please input a number >>> "); scanf("% ...

  7. 使用注解匹配Spring Aop切点表达式

    Spring中的类基本都会标注解,所以使用注解匹配切点可以满足绝大部分需求 主要使用@within()/@target @annotaton() @args()等... 匹配@Service类中的所有 ...

  8. .net使用正则表达式校验、匹配字符工具类

    开发程序离不开数据的校验,这里整理了一些数据的校验.匹配的方法: /// <summary> /// 字符(串)验证.匹配工具类 /// </summary> public c ...

  9. webpack配置别名alias出现的错误匹配

    @(webpack) webpack是一款功能强大的前端构建工具,不仅仅是针对js,它也可通过各种loader来构建相关的less,html,image等各种资源,将webpack配合流程制定工具gu ...

随机推荐

  1. ■SQL注入自学[第三学:注入点的读写、out_file]

    00x1 判断是否可读 code: http:.php?id and (select count(*) from mysql.user) >0--/*返回正确的话,说明没有是有读的权限.返回错误 ...

  2. [原创]DELPHI木马DIY之生成服务端

    文章作者:上帝的禁区信息来源:邪恶八进制信息安全团队(www.eviloctal.com)DELPHI木马DIY之生成服务端   我在这里就生成简单的服务端,为什么不先讲服务端的隐藏?因为我觉得生成服 ...

  3. BZOJ1050 [HAOI2006]旅行

    其实这道题根本不用最短路算法... 我们可以就把边从小到大排序,那么只需要枚举大小两个端点,把中间的边都加进去判断联通性即可. 判断联通性显然用的是并查集. #include <cstdio&g ...

  4. TFS和VSS的简单对比

    概念: TFS:Team Foundation Server(通常记作“TFS”) 是一种为 Microsoft 产品提供 源代码管理. 数据收集. 报告和项目跟踪,而为协作 软件开发 的项目. 可作 ...

  5. webdriver+python 对三大浏览器的支持

    1.在IE浏览器上运行测试脚本,首先需要下载IEDriverServer.exe(http://code.google.com/p/selenium/downloads/list,根据浏览器的版本下载 ...

  6. ReverseString

    [本文链接] http://www.cnblogs.com/hellogiser/p/reverse-string.html reverse string [代码]  C++ Code  123456 ...

  7. centos 单独安装PHP的mysql和mysqli扩展

    2013年11月22日 11:25:41 Linux centos 6.3 最小化安装 mysql 5.5 php 5.4 安装PHP时只是 ./configure --prefix=/**** 并没 ...

  8. Light OJ 1296 - Again Stone Game (博弈sg函数递推)

    F - Again Stone Game Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu ...

  9. python基础——字符串和编码

    python基础——字符串和编码 字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题. 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用 ...

  10. Material Design入门

    本文主要包括以下内容 ToolBar的使用 RecyclerView的定义与使用 ToolBar 风格 (style) 界面 (layout) 程序 (java) 首先自定义一个theme,并将App ...