题目大意

给定\(n\)个字符串和\(k\)

对于每个字符串,输出它有多少个子串至少是\(k\)个字符串的子串(包括自己)

分析

建出广义后缀自动机

至少是\(k\)个字符串的子串就是求子树内不同数个数

考虑怎么统计答案

不要做本质不同子串做傻了

这题是问有多少个子串,子串相同位置不同是可以重复统计的

直接找字符串的每个后缀,它们前缀对应的子串开始位置都是不同的,不会算重

统计的就是每个后缀对应的节点 到跟路径上 有多少合法

dfs预处理一下树上前缀和就好

solution

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int M=200007; inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
} LL sum[M];
int n,m;
char s[M];
int last,tot;
int stp[M];
int ch[M][26];
int fa[M];
int que[M],ed[M];
int q[M],tq;
int dfn[M],sz[M],tdfn;
int pre[M][20],Mx,dep[M]; struct edge{int y,nxt;};
struct vec{
int g[M],te;
edge e[M];
vec(){memset(g,0,sizeof(g));te=0;}
void clear(){memset(g,0,sizeof(g));te=0;}
inline void push(int x,int y){e[++te].y=y;e[te].nxt=g[x];g[x]=te;}
inline int& operator () (int &x){return g[x];}
inline edge& operator [] (int &x){return e[x];}
}go; int newnode(int ss){
stp[++tot]=ss;
return tot;
} int ext(int p,int q,int d){
int nq=newnode(stp[p]+1);
fa[nq]=fa[q]; fa[q]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
for(;p&&ch[p][d]==q;p=fa[p]) ch[p][d]=nq;
return nq;
} int sam(int p,int d){
int np=ch[p][d];
if(np) return (stp[p]+1==stp[np]) ? np : ext(p,np,d); np=newnode(stp[p]+1);
for(;p&&!ch[p][d];p=fa[p]) ch[p][d]=np;
if(!p) fa[np]=1;
else{
int q=ch[p][d];
fa[np]= (stp[p]+1==stp[q]) ? q : ext(p,q,d);
}
return np;
} int dfs(int x){
dfn[x]=++tdfn;
sz[x]=1;
int p,y;
for(p=go(x);p;p=go[p].nxt){
y=go[p].y;
dep[y]=dep[x]+1;
pre[y][0]=x;
dfs(y);
sz[x]+=sz[y];
}
} bool cmp(int x,int y){
return dfn[x]<dfn[y];
} int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int t=Mx;t>=0;t--)
if(dep[pre[x][t]]>=dep[y]) x=pre[x][t];
if(x==y) return x;
for(int t=Mx;t>=0;t--)
if(pre[x][t]!=pre[y][t]) x=pre[x][t],y=pre[y][t];
return pre[x][0];
} int c[M]; inline int lb(int x){return x&(-x);} inline int add(int x,int d){
for(;x<=tdfn;x+=lb(x)) c[x]+=d;
} inline int get(int x){
int res=0;
for(;x>0;x-=lb(x)) res+=c[x];
return res;
} inline int get(int x,int y){
return get(y)-get(x-1);
} void vtree(int l,int r){
int i,x,p,y;
tq=0;
for(i=l;i<=r;i++) q[++tq]=que[i];
sort(q+1,q+tq+1,cmp);
for(i=1;i<=tq;i++) add(dfn[q[i]],1);
for(i=2;i<=tq;i++) add(dfn[LCA(q[i],q[i-1])],-1);
} void gao(int x){
int p,y;
for(p=go(x);p;p=go[p].nxt){
y=go[p].y;
if(get(dfn[y],dfn[y]+sz[y]-1)>=m) sum[y]=sum[x]+stp[y]-stp[x];
else sum[y]=sum[x];
gao(y);
}
} int main(){ int i,j,p; n=rd(),m=rd();
tot=1;
for(i=1;i<=n;i++){
scanf("%s",s+1);
last=1;
p=strlen(s+1);
for(j=p;j>0;j--){
last=sam(last,s[j]-'a');//***
que[++tq]=last;
}
ed[i]=tq;
}
for(i=2;i<=tot;i++) go.push(fa[i],i);
dfs(1);
Mx=log2(tot);
for(j=1;j<=Mx;j++)
for(i=1;i<=tot;i++) pre[i][j]=pre[pre[i][j-1]][j-1];
for(i=1;i<=n;i++) vtree(ed[i-1]+1,ed[i]);
gao(1);
for(i=1;i<=n;i++){
LL ans=0;
for(j=ed[i-1]+1;j<=ed[i];j++)
ans+=sum[que[j]];
printf("%lld\n",ans);
} return 0;
}

bzoj 3277 串 后缀树+子树不同数个数的更多相关文章

  1. BZOJ 3277 串 & BZOJ 3473 字符串 (广义后缀自动机、时间复杂度分析、启发式合并、线段树合并、主席树)

    标签那么长是因为做法太多了... 题目链接: (bzoj 3277) https://www.lydsy.com/JudgeOnline/problem.php?id=3277 (bzoj 3473) ...

  2. BZOJ 3277 串 (广义后缀自动机)

    3277: 串 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 309 Solved: 118 [Submit][Status][Discuss] De ...

  3. BZOJ 3277: 串/ BZOJ 3473: 字符串 ( 后缀数组 + RMQ + 二分 )

    CF原题(http://codeforces.com/blog/entry/4849, 204E), CF的解法是O(Nlog^2N)的..记某个字符串以第i位开头的字符串对答案的贡献f(i), 那么 ...

  4. HDU 5919 Sequence II(主席树+区间不同数个数+区间第k小)

    http://acm.split.hdu.edu.cn/showproblem.php?pid=5919 题意:给出一串序列,每次给出区间,求出该区间内不同数的个数k和第一个数出现的位置(将这些位置组 ...

  5. bzoj 3277 串 && bzoj 3473 字符串 && bzoj 2780 [Spoj]8093 Sevenk Love Oimaster——广义后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277 https://www.lydsy.com/JudgeOnline/problem.p ...

  6. bzoj 3277: 串 & bzoj 3473: 字符串【后缀自动机||后缀数组】

    建一个广义后缀自动机(每加完一个串都返回root),在parent树上dpsum记录合法长度,打着时间戳往上跳,最后每个串在自动机上跑一变统计答案即可. 后缀数组理解起来可能方便一点,但是难写,就只说 ...

  7. bzoj 3277: 串

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

  8. SPOJ DQUERY D-query(主席树 区间不同数个数)

    题意:问你区间有几个不同的数 思路:主席树nb.我们知道主席树每一个root都存着一棵权值线段树,现在我们在每个root中存位置,也就是01表示这个位置存不存在.然后我们用一个fa[a[i]]表示a[ ...

  9. 从Trie树(字典树)谈到后缀树

    转:http://blog.csdn.net/v_july_v/article/details/6897097 引言 常关注本blog的读者朋友想必看过此篇文章:从B树.B+树.B*树谈到R 树,这次 ...

随机推荐

  1. caller、callee的用法及区别

    1 :caller 返回一个调用当前函数的引用 如果是由顶层调用的话 则返回null (举个栗子哈 caller给你打电话的人  谁给你打电话了 谁调用了你 很显然是下面a函数的执行 只有在打电话的时 ...

  2. Linux入门-第九周

    1.判断UID是否大于等于500,如果为真就显示为普通用户,如果为假就显示为系统或管理用户 AWK简介:awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报 ...

  3. php微信分享demo

    php微信分享demo //定义JSSDK类 <?php class JSSDK { private $appId; private $appSecret; private $redis; pu ...

  4. cmf5分页相关

    //分页配置在app/config.php 'paginate' => [ 'type' => '\cmf\paginator\Bootstrap', 'var_page' => ' ...

  5. vue.js 三(数据交互)isomorphic-fetch

    至于fetch的介绍,在这里就不多说了,官方和网络上的说明不少 之前使用jquery的Ajax朋友,可以尝试一下使用一下这个新的api 推荐使用isomorphic-fetch,兼容Node.js和浏 ...

  6. hadoop核心组件概述及hadoop集群的搭建

    什么是hadoop? Hadoop 是 Apache 旗下的一个用 java 语言实现开源软件框架,是一个开发和运行处理大规模数据的软件平台.允许使用简单的编程模型在大量计算机集群上对大型数据集进行分 ...

  7. 排序算法合集(Java)

    整理了一下常用的排序算法,算法过程和示意图不详细讲,百度很多,只列代码,如有错误,还望大家指出. 1.冒泡排序 public static void bubbleSort(int[] a){ for( ...

  8. python爬虫的基本思路

    爬虫:请求网站并提取数据的自动化程序. 流程: 发送请求 -> 获取数据 -> 解析数据 -> 存储数据

  9. 51nod 1202 不同子序列个数(计数DP)

    1202 子序列个数 基准时间限制:1 秒 空间限制:131072 KB 分值: 40      子序列的定义:对于一个序列a=a[1],a[2],......a[n].则非空序列a'=a[p1],a ...

  10. unity安装记录

    官网直接下载(http://unity3d.com/cn/) 下载完后,会要求输入账号密码.我是先在官网进行一个账号注册,然后登陆即可. 首先会要你输入一个已有的邮箱,进行认证.进入自己邮箱,点击链接 ...