题目大意:

给你$n$个大串和$m$个询问,每次给出一个字符串$s$询问在多少个大串中出现过

好神的一道题

对$n$个大串建出广义$SAM$,建出$parent$树

把字符串$s$放到$SAM$里跑,找到能表示字符串$s$的节点$x$

问题转化为在$parent$树中,$x$节点的子树内,有多少个编号不同的$endpos$节点

把树拍扁,转化为$dfs$序

不就是在序列上跑HH的项链么,离线树状数组维护一下就好

一个节点可能有多个不同串$endpos$标记,用$vector$存一下串的编号就行了

注意索引不要写错,不要把数组开小了

 #include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 105000
#define S1 (N1<<1)
#define T1 (N1<<2)
#define ll long long
#define uint unsigned int
#define rint register int
#define il inline
#define inf 0x3f3f3f3f
#define idx(X) (X-'a')
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
} int n,m,len,tot;
char str[N1];
struct Edge{
int to[T1],nxt[T1],head[T1],cte;
void ae(int u,int v){
cte++;to[cte]=v;nxt[cte]=head[u],head[u]=cte;}
}E,Q;
struct BIT{
int sum[T1],ma;
void upd(int x,int w){
for(int i=x;i<=ma;i+=(i&(-i)))
sum[i]+=w;}
int query(int x){
int ans=;
for(int i=x;i>;i-=(i&(-i)))
ans+=sum[i];
return ans;}
}b;
namespace SAM{
int trs[S1][],pre[S1],dep[S1],la;
vector<int>ed[S1];
void init(){tot=la=;}
void reduct(){la=;}
void insert(int x,int id)
{
int p=la,q,np=++tot,nq;la=np;
dep[np]=dep[p]+;
ed[np].push_back(id);
for(;p&&!trs[p][x];p=pre[p]) trs[p][x]=np;
if(!p) pre[np]=;
else{
q=trs[p][x];
if(dep[q]==dep[p]+) pre[np]=q;
else{
pre[nq=++tot]=pre[q];
pre[q]=pre[np]=nq;
dep[nq]=dep[p]+;
memcpy(trs[nq],trs[q],sizeof(trs[q]));
for(;p&&trs[p][x]==q;p=pre[p]) trs[p][x]=nq;
}
}
}
void Build_Edge()
{
for(int i=;i<=tot;i++)
E.ae(pre[i],i);
}
int find(char *str,int L)
{
int x=;
for(int i=;i<=L;i++){
x=trs[x][idx(str[i])];
if(!x) return ;
}return x;
}
};
namespace Seq{
int st[T1],ed[T1],to[T1],ans[T1],la[T1],cnt;
void dfs1(int x)
{
st[x]=++cnt;
for(int j=E.head[x];j;j=E.nxt[j])
dfs1(E.to[j]);
ed[x]=++cnt;
to[cnt]=x;
}
void solve()
{
dfs1();
b.ma=cnt;
int x,v;
for(int i=;i<=m;i++)
{
scanf("%s",str+);
len=strlen(str+);
x=SAM::find(str,len);
if(x) Q.ae(ed[x],i);
}
for(int i=;i<=cnt;i++)
{
x=to[i];
for(int j=;j<SAM::ed[x].size();j++)
{
v=SAM::ed[x][j];
if(!la[v]) b.upd(i,),la[v]=i;
else b.upd(la[v],-),la[v]=i,b.upd(i,);
}
for(int j=Q.head[i];j;j=Q.nxt[j])
{
v=Q.to[j];
ans[v]=b.query(ed[x])-b.query(st[x]);
}
}
for(int i=;i<=m;i++)
printf("%d\n",ans[i]);
} }; int main()
{
//freopen("t2.in","r",stdin);
scanf("%d%d",&n,&m);
SAM::init();
for(int i=;i<=n;i++)
{
scanf("%s",str+);
len=strlen(str+);
for(int j=;j<=len;j++)
SAM::insert(idx(str[j]),i);
SAM::reduct();
}
SAM::Build_Edge();
Seq::solve();
return ;
}

最新文章

  1. 算法(第4版)-1.5 案例研究:union-find算法
  2. AndFix热修复 —— 实战与源码解析
  3. IIS线程池与ASP.NET线程池
  4. quartz中关键类
  5. Oracle—用户管理的完全恢复(四)
  6. C# winform 若要在加载设计器前避免可能发生的数据丢失,必须纠正以下错误
  7. django: startproject
  8. [iOS]数据库第三方框架FMDB详细讲解
  9. jQuery验证表单格式
  10. WebRTC学习笔记_Demo收集
  11. SourceTree基础
  12. POJ - 1797 Heavy Transportation 单源最短路
  13. hdu 4897 树链剖分(重轻链)
  14. 使用 NPOI 导出 Excel 文件
  15. django的配置文件字符串是怎么导入的?
  16. 非常详细的Docker学习教程
  17. 3)django-路由系统url
  18. js中的值类型和引用类型的区别
  19. Python:在windows下创建虚拟环境
  20. HDU 2222 Keywords Search(AC自动机模板题)

热门文章

  1. Vue学习之路第十二篇:为页面元素设置内联样式
  2. javaScript原型、闭包和异步操作
  3. webstorm + babel
  4. P1421 小玉买文具
  5. FFMpeg 常用命令格式转换,视频合成
  6. node+express框架中连接使用mysql经验总结
  7. hdu 1868 水
  8. ie版本
  9. BA-siemens-insight_ppcl_adapts函数用法
  10. JavaSript 基础学习笔记