Description

字符串是oi界常考的问题。现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中
至少k个字符串的子串(注意包括本身)。

Input

第一行两个整数n,k。
接下来n行每行一个字符串。
n,k,l<=100000

Output

输出一行n个整数,第i个整数表示第i个字符串的答案。

Sample Input

3 1
abc
a
ab

Sample Output

6 1 3

解题思路:

k个嘛,好像可以离线树状数组QAQ,具体的像这样,只不过需要将所有节点都询问一遍。

最后,找子串嘛,短的不多于k个长的肯定也不行,利用这个性质,只要不够k就跳pre,直到大于等于k。

而以这个节点为后缀的子串共有len个,ans+=len就好了。

代码:

 #include<cstdio>
#include<cstring>
#include<algorithm>
const int N=;
struct sant{
int tranc[];
int len;
int pre;
}s[N];
struct pnt{
int hd;
int ind;
int oud;
int col;
int ans;
}p[N];
struct ent{
int twd;
int lst;
}e[N];
struct int_2{
int l;
int r;
int no;
}d[N];
int n,k;
int siz;
int dfn;
int cnt;
int fin;
char tmp[N];
int ll[N],rr[N];
int col[N];
int lst[N];
int line[N];
int str[N];
int lowbit(int x)
{
return x&(-x);
}
void update(int pos,int x)
{
while(pos&&pos<=dfn)
{
line[pos]+=x;
pos+=lowbit(pos);
}
return ;
}
int query(int pos)
{
int ans=;
while(pos)
{
ans+=line[pos];
pos-=lowbit(pos);
}
return ans;
}
bool cmp(int_2 x,int_2 y)
{
return x.r<y.r;
}
void ade(int f,int t)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
p[f].hd=cnt;
return ;
}
void Insert(int c,int pl)
{
int nwp,nwq,lsp,lsq;
nwp=++siz;
s[nwp].len=s[fin].len+;
p[nwp].col=pl;
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;
}
void Dfs(int x)
{
p[x].ind=++dfn;
col[dfn]=p[x].col;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
Dfs(to);
}
p[x].oud=++dfn;
col[dfn]=p[x].col;
}
int main()
{
scanf("%d%d",&n,&k);
if(k>n)
{
for(int i=;i<=n;i++)
printf("%d ",);
return ;
}
fin=++siz;
for(int i=;i<=n;i++)
{
ll[i]=rr[i-]+;
rr[i]=rr[i-];
fin=;
scanf("%s",tmp);
int len=strlen(tmp);
for(int j=;j<len;j++)
str[++rr[i]]=tmp[j]-'a';
for(int j=ll[i];j<=rr[i];j++)
{
Insert(str[j],i);
}
} for(int i=;i<=siz;i++)
ade(s[i].pre,i);
Dfs();
for(int i=;i<=siz;i++)
d[i]=(int_2){p[i].ind,p[i].oud,i};
std::sort(d+,d+siz+,cmp);
int r=;
for(int i=;i<=siz;i++)
{
while(r<=d[i].r)
{
if(!col[r])
{
r++;
continue;
}
if(lst[col[r]])
update(lst[col[r]],-);
update(r,);
lst[col[r]]=r;
r++;
}
r--;
p[d[i].no].ans=query(d[i].r)-query(d[i].l-);
}
for(int i=;i<=n;i++)
{
int ans=;
int root=;
for(int j=ll[i];j<=rr[i];j++)
{
root=s[root].tranc[str[j]];
while(p[root].ans<k)
root=s[root].pre;
ans+=s[root].len;
}
printf("%d ",ans);
}
puts("");
return ;
}

BZOJ3277: 串(后缀自动机,Parent树,Dfs序)的更多相关文章

  1. [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增

    题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...

  2. P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队+dfs序)

    P2336 [SCOI2012]喵星球上的点名 名字怎么存?显然是后缀自动机辣 询问点到多少个喵喵喵其实就是 查询后缀自动机上parent树的一个子树 于是我们考虑莫队 怎么树上莫队呢 我们用dfs序 ...

  3. 洛谷2414(构建ac自动机fail树dfs序后遍历Trie树维护bit及询问答案)

    要点 这是一道蔡队题,看我标题行事 任意询问y串上有多少个x串,暴力找每个节点是不是结尾肯定是炸的,考虑本质:如果某节点是x的结尾,根据ac自动机的性质,x一定是此(子)串后缀.又有每个Trie节点的 ...

  4. BZOJ 2905: 背单词 AC自动机+fail树+dfs序+线段树

    Description 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使得其中的每个单词是后一个单词的子串,最大化子序列中W的和. Input 第一行一个整数TEST,表示数据组 ...

  5. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  6. 【Codeforces163E】e-Government AC自动机fail树 + DFS序 + 树状数组

    E. e-Government time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...

  7. 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2022  Solved: 1158[Submit][Sta ...

  8. luogu5212/bzoj2555 substring(后缀自动机+动态树)

    对字符串构建一个后缀自动机. 每次查询的就是在转移边上得到节点的parent树中后缀节点数量. 由于强制在线,可以用动态树维护后缀自动机parent树的子树和. 注意一个玄学的优化:每次在执行连边操作 ...

  9. 洛谷P4493 [HAOI2018]字串覆盖(后缀自动机+线段树+倍增)

    题面 传送门 题解 字符串就硬是要和数据结构结合在一起么--\(loj\)上\(rk1\)好像码了\(10k\)的样子-- 我们设\(L=r-l+1\) 首先可以发现对于\(T\)串一定是从左到右,能 ...

  10. 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)

    题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...

随机推荐

  1. 基于Linux的智能家居的设计(2)

    1  系统整体设计方案 智能家居系统的是一个实时查询家庭的温湿度.照明控制.自己主动控制的设定.集家庭娱乐.智能安防为一体,大量数据快处理.可靠的系统,因此在硬件和软件上都有非常大的要求,因此在这里进 ...

  2. 37.微信跳一跳辅助开发(C语言+EasyX)

    一.开发环境 开发环境 使用语言:C/C++ IDE:VS2010+ 其他三方库 EasyX(http://www.easyx.cn/downloads/) ADB(链接:https://pan.ba ...

  3. Hadoop的多节点集群详细启动步骤(3或5节点)

    版本1 利用自己写的脚本来启动,见如下博客 hadoop-2.6.0-cdh5.4.5.tar.gz(CDH)的3节点集群搭建 hadoop-2.6.0.tar.gz的集群搭建(3节点) hadoop ...

  4. 线程框架Executor的用法举例

    java5线程框架Executor的用法举例 Executor 是 java5 下的一个多任务并发执行框架(Doug Lea),可以建立一个类似数据库连接池的线程池来执行任务.这个框架主要由三个接口和 ...

  5. 常用sql语句及案例

    目录 1)基本 2)数学函数 3)rownum 4)分页 5)时间处理 6)字符函数 7)to_number 8)聚合函数 9)学生选课 10)图书馆借阅 基本 --新建表: create table ...

  6. 把华为交换机设置成时钟源服务器(NTP)

    把华为交换机设置成时钟源服务器(NTP),提供给下面客户端Linux服务器使用, 1,先设置交换机的时区,和正确时间 # 假设地理位置在中国北京,设置本地时区名称为BJ. 如果系统默认的UTC是伦敦时 ...

  7. C2mini 摄像头添加 到 7832N 录像机方法

    1.在YS7.com 把2个设备全部添加 (录像机也可以通过手机添加) 2.在录像机里添加摄像头 注: 如出现 “未知错误”可能为录像机版本过低造成.

  8. nginx下修改svn配置

    最近公司的SVN服务器地址做了变更,而我用的操作系统是Ubuntu操作系统,我也不想把以前下载的代码重新进行修改,我想通过修改svn地址,应该可以,终于在网上通过查找资料,找到了解决的方法:      ...

  9. 【Uva 10118】Free Candies

    [Link]: [Description] 有4堆书; 每本书编号从1..20 每堆书都是N本; 然后每次只能从任意一堆的堆顶拿一本书装到自己的口袋里; 你的口袋最多容纳5本书; 当你的口袋里有两本一 ...

  10. 从零開始的Android新项目7 - Data Binding入门篇

    Data Binding自从去年的Google I/O公布到至今,也有近一年的时间了.这一年来,从Beta到如今比較完好的版本号.从Android Studio 1.3到如今2.1.2的支持,能够说D ...