后缀自动机+线段树

先建出\(sam\),统计一遍每个点的\(right\)集合大小\(siz\),对于\(siz=1\)的点\(x\),他所代表的子串只会出现一次,设\(y=fa[x]\),则这个点代表的子串即为\((1...len[x]-len[y],len[x])\),对于子串\((len[x]-len[y],len[x])\)的每一个点,这个子串都是他的识别子串,长度固定\(len[y]+1\),而对于一个点\(i\in[1,len[x]-len[y]-1]\),子串\((i,len[x])\)一定是他的一个识别子串,长度\(len[x]+1-i\)。可以用两棵线段树分别存\(len[y]+1\)与\(len[x]+1\),单点查询最小值得到答案

#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
struct xdt{
int poi[maxn<<2],lazy[maxn<<2];
void updata(int x){
poi[x]=min(poi[x<<1],poi[x<<1|1]);
}
void pushdown(int x){
if(!lazy[x]) return;
poi[x<<1]=min(poi[x<<1],lazy[x]);
lazy[x<<1]=lazy[x<<1]?min(lazy[x<<1],lazy[x]):lazy[x];
poi[x<<1|1]=min(poi[x<<1|1],lazy[x]);
lazy[x<<1|1]=lazy[x<<1|1]?min(lazy[x<<1|1],lazy[x]):lazy[x];
lazy[x]=0;
}
void build(int l,int r,int now){
poi[now]=0x7fffffff;
if(l==r) return;
int mid=l+r>>1;
build(l,mid,now<<1);
build(mid+1,r,now<<1|1);
}
void revise(int lc,int rc,int l,int r,int now,int z){
if(lc==l&&rc==r){
poi[now]=min(poi[now],z);
if(lazy[now]==0) lazy[now]=z;
else lazy[now]=min(lazy[now],z);
return;
}
pushdown(now);
int mid=lc+rc>>1;
if(l<=mid) revise(lc,mid,l,min(mid,r),now<<1,z);
if(r>mid) revise(mid+1,rc,max(mid+1,l),r,now<<1|1,z);
updata(now);
}
int query(int lc,int rc,int x,int now){
if(lc==rc) return poi[now];
pushdown(now);
int mid=lc+rc>>1;
if(x<=mid) return query(lc,mid,x,now<<1);
else return query(mid+1,rc,x,now<<1|1);
}
}t1,t2;
struct SAM{
int son[maxn][26],len[maxn],siz[maxn],fa[maxn],tax[maxn],a[maxn];
int tot,last,n;
char s[maxn];
void insert(int x){
int p=last,np=++tot;
len[np]=len[p]+1;
siz[np]=1;
while(~p&&!son[p][x])
son[p][x]=np,p=fa[p];
if(p==-1)
fa[np]=0;
else{
int q=son[p][x];
if(len[q]==len[p]+1)
fa[np]=q;
else{
int nq=++tot;
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq]=fa[q];
len[nq]=len[p]+1;
fa[q]=fa[np]=nq;
while(~p&&son[p][x]==q)
son[p][x]=nq,p=fa[p];
}
}
last=np;
}
void Qsort(){
for(int i=0;i<=n;i++) tax[i]=0;
for(int i=1;i<=tot;i++) tax[len[i]]++;
for(int i=1;i<=n;i++) tax[i]+=tax[i-1];
for(int i=1;i<=tot;i++) a[tax[len[i]]--]=i;
}
void ycl(){
last=tot=0,fa[0]=-1;
for(int i=1;i<=n;i++) insert(s[i]-'a');
Qsort();
for(int i=tot;i>=1;i--) siz[fa[a[i]]]+=siz[a[i]];
t1.build(1,n,1),t2.build(1,n,1);
for(int i=1;i<=tot;i++)
if(siz[i]==1){
int l=len[i]-len[fa[i]],r=len[i];
t1.revise(1,n,l,r,1,r-l+1);
// printf("->%d\n",t1.query(1,n,2,1));
if(l!=1) t2.revise(1,n,1,l-1,1,r+1);
}
}
void query(){
// printf("->%d\n",t1.query(1,n,2,1));
for(int i=1;i<=n;i++)
printf("%d\n",min(t1.query(1,n,i,1),t2.query(1,n,i,1)-i));
}
}sam;
int main(){
// freopen(".in","r",stdin);
scanf("%s",sam.s+1),sam.n=strlen(sam.s+1);
sam.ycl();
sam.query();
return 0;
}


BZOJ-1396: 识别子串的更多相关文章

  1. BZOJ 1396: 识别子串( 后缀数组 + 线段树 )

    这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...

  2. BZOJ 1396:识别子串 SA+树状数组+单调队列

    1396: 识别子串 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 381  Solved: 243[Submit][Status][Discuss] ...

  3. BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)

    题目链接 SAM:能成为识别子串的只有那些|right|=1的节点代表的串. 设这个节点对应原串的右端点为r[i],则如果|right[i]|=1,即\(s[\ [r_i-len_i+1,r_i-le ...

  4. bzoj 1396 识别子串 后缀树+线段树

    题目大意 给定一个长度\(\le100000\)的字符串 求每一个位置的最短识别子串 对于位置\(x\),能识别子串\(s[i...j]\)的条件是 1.\(i\le x \le j\) 2.\(s[ ...

  5. BZOJ 1396 识别子串 (后缀自动机、线段树)

    手动博客搬家: 本文发表于20181221 00:58:26, 原地址https://blog.csdn.net/suncongbo/article/details/85150962 嗯,以后博客内容 ...

  6. ●BZOJ 1396 识别子串

    题链: http://www.joyoi.cn/problem/tyvj-2301(非权限OI患者,苟且在joyoi...)题解: 后缀自动机,线段树 先对原串建立后缀自动机,不难发现, 会影响答案是 ...

  7. bzoj 1396: 识别子串 && bzoj 2865: 字符串识别【后缀数组+线段树】

    根据height数组的定义,和当前后缀串i最长的相同串的长度就是max(height[i],height[i+1]),这个后缀贡献的最短不同串长度就是len=max(height[i],height[ ...

  8. BZOJ 1396 识别子串 (后缀自动机+线段树)

    题目大意: 给你一个字符串S,求关于每个位置x的识别串T的最短长度,T必须满足覆盖x,且T在S中仅出现一次 神题 以节点x为结尾的识别串,必须满足它在$parent$树的子树中只有一个$endpos$ ...

  9. bzoj 1396: 识别子串【SAM+线段树】

    建个SAM,符合要求的串显然是|right|==1的节点多代表的串,设si[i]为right集合大小,p[i]为right最大的r点,这些都可以建出SAM后再parent树上求得 然后对弈si[i]= ...

  10. BZOJ bzoj1396 识别子串

    题面: bzoj1396 题解: 先建出SAM,并计算right集合大小.显然符合条件的点的right集合大小为1. 对于每个right集合为1的状态显然可以算出这些状态的pos以及maxlen和mi ...

随机推荐

  1. UVALive 5873 (几何+思维)

    唉 被秀了... 还是太弱,说好的数形结合呢,列个式子出来后就被吓到了,然后就懵逼了. 题意: 有一条狗,从原点出发,沿n个向量走,每个向量只走一次,沿着一个向量(x,y)走时,既可以往(x,y)方向 ...

  2. 【BZOJ4247】挂饰 背包

    [BZOJ4247]挂饰 Description JOI君有N个装在手机上的挂饰,编号为1...N. JOI君可以将其中的一些装在手机上. JOI君的挂饰有一些与众不同——其中的一些挂饰附有可以挂其他 ...

  3. Android获取应用程序的信息

    1.获取应用程序的版本号: private String getAppVersionName() { String versionName = ""; try { PackageM ...

  4. 前端 为什么我选择用框架而不是Jquery

    对于很多习惯用Jquery的前端甚至后端,都很不解,为什么不用Jquery而是框架.觉得框架学起来麻烦,成本高,今天我以我浅薄的知识来总结一下为什么前台开发选择用框架: 前台开发,主要的性能是卡在回流 ...

  5. 利用Google Analytics API实现自己的统计报表

    Google Analytics 简称 GA,功能实在是太强大了,正因如此,导致调研GA API花费了大量的时间,太多的名词需要梳理. 正确的学习步骤是: 首先,找个有权限的账号,登录GA(https ...

  6. /proc/kcore

    [root@b proc]# ls -lh /proc/kcore-r-------- 1 root root 128T Sep 29 09:39 /proc/kcore[root@b proc]# ...

  7. Oracle DBA的学习(笔记)

    1.软件任务分组:系统分析师.系统设计师.程序员.测试人员.开发dba.系统架构师.实施人员. 2.常用设计图:活动图.用例图.类图.序列图. 2010-9-15(dba学习) 1.1 Oracle产 ...

  8. 在Tomcat配置JNDI数据源的三种方式

    最近使用到了在tomcat下配置数据源的内容,在这里转载一篇文章记录下 转载自: http://blog.csdn.net/dyllove98/article/details/7706218 在我过去 ...

  9. Delphi重定义的消息结构

    // 除去DDE和MDI消息,一共159个消息,其中部分消息仅仅的转定义 // 普通消息,有两个参数和结果 PMessage = ^TMessage; TMessage = packed record ...

  10. element-ui中下拉菜单中的@click事件不会触发的问题

    只需要将@click=“fun()”改为@click.native=“fun()”,即可监听下拉菜单的点击事件. 如图所示: 嗯,就酱~