题目

【题目描述】

一般地,对于一个字符串 S,和 S 中第 $ i $ 个字符 x,定义子串 $ T=S(i.j) $ 为一个关于 x 的识别子申,当且仅当:
  1.$ i \leq x \leq j $
  2.T 在 S 巾只出现一次
比如,对于 banana 的第 $ 5 $ 个字符,“nana”, “anan”,“anana”, “nan”,“banan” 和“banana”都是关于它的识别子串。
说你写一个程序,计算出对对于一个字符串 S,关于 S 的每一位的最短识别子串的长度。

【输入格式】

一行,一个由小写字母组成的字符串 S, 长度不超过 $ 10^5 $

【输出格式】

L 行,每行一个整数,第 $ i $ 行的数据表示关于 S 的第 $ i $ 个元素的最短识别子串有多长.

【样例输入】

agoodcookcooksgoodfood

【样例输出】

1
2
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4

【数据范围与提示】

对于 20% 的数据 L<=200

对于 40% 的数据 L<=5000

对于 60% 的数据 L<=20000

对于 100% 的数据 L<=100000

题解

可以发现,对于每一个唯一识别的子串,都可以更新一段答案

可以发现,在后缀自动机上的每一个叶子节点 $ x $,都是一段唯一识别的子串

考虑更新,记 $ l=len(x)-len(fa(x)),r=len(x) $,那么对于 $ [1,l-1] $ 的贡献为 $ r-i+1 $,对于 $ [l,r] $ 的贡献为 $ r-l+1 $

可以把 $r-i+1$ 的 $ i $ 提出,转化为 $query(i)-i$,开两棵线段树分别统计即可

代码

 #include<bits/stdc++.h>
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
int R(){
int x;bool f=;char ch;_(!)if(ch=='-')f=;x=ch^;
_()x=(x<<)+(x<<)+(ch^);return f?x:-x;}
const int N=1e6+;
int n,las=,cnt=,Rt=;
char s[N];bool f[N];
struct node{int ch[],fa,len;}tr[N];
void extend(int c){
int p=las,np=las=++cnt,q,nq;
tr[np].len=tr[p].len+;
while(!tr[p].ch[c]&&p)
tr[p].ch[c]=np,p=tr[p].fa;
if(!p)return void(tr[np].fa=Rt);
if(tr[p].len+==tr[q=tr[p].ch[c]].len)return void(tr[np].fa=q);
tr[nq=++cnt].len=tr[p].len+;
memcpy(tr[nq].ch,tr[q].ch,sizeof tr[q].ch);
tr[nq].fa=tr[q].fa,tr[np].fa=tr[q].fa=nq;
while(p&&tr[p].ch[c]==q)
tr[p].ch[c]=nq,p=tr[p].fa;
return;
}
class seg{
private:
#define Ls rt<<1
#define Rs rt<<1|1
public:
int tr[N];
seg(){memset(tr,0x3f,sizeof tr);}
void update(int rt,int l,int r,int ql,int qr,int v){
if(ql>qr)return;
if(ql<=l&&qr>=r)return void(tr[rt]=min(tr[rt],v));
int mid=l+r>>;
if(ql<=mid)update(Ls,l,mid,ql,qr,v);
if(qr>mid)update(Rs,mid+,r,ql,qr,v);
return;
}
int query(int rt,int l,int r,int k){
if(l==r)return tr[rt];
int mid=l+r>>;
if(k<=mid)return min(tr[rt],query(Ls,l,mid,k));
else return min(tr[rt],query(Rs,mid+,r,k));
}
}T1,T2;
int main(){
scanf("%s",s+),n=strlen(s+);
for(int i=;i<=n;i++)extend(s[i]-'a');
for(int i=;i<=cnt;i++)f[tr[i].fa]=;
for(int i=;i<=cnt;i++)
if(!f[i]){
int x=tr[i].len-tr[tr[i].fa].len,y=tr[i].len;
T1.update(,,n,,x-,y+),T2.update(,,n,x,y,tr[tr[i].fa].len+);
}
for(int i=;i<=n;i++)
printf("%d\n",min(T1.query(,,n,i)-i,T2.query(,,n,i)));
return ;
}

识别子串 (string)——后缀自动机+线段树的更多相关文章

  1. bzoj千题计划318:bzoj1396: 识别子串(后缀自动机 + 线段树)

    https://www.lydsy.com/JudgeOnline/problem.php?id=1396 后缀自动机的parent树上,如果不是叶子节点,那么至少有两个子节点 而一个状态所代表子串的 ...

  2. BZOJ1396&2865 识别子串 【后缀自动机 + 线段树】

    题目 输入格式 一行,一个由小写字母组成的字符串S,长度不超过10^5 输出格式 L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长. 输入样例 agoodcookcooksg ...

  3. BZOJ1396: 识别子串(后缀自动机 线段树)

    题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...

  4. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  5. 【BZOJ4556】[TJOI2016&HEOI2016] 字符串(后缀自动机+线段树合并+二分)

    点此看题面 大致题意: 给你一个字符串\(s\),每次问你一个子串\(s[a..b]\)的所有子串和\(s[c..d]\)的最长公共前缀. 二分 首先我们可以发现一个简单性质,即要求最长公共前缀,则我 ...

  6. [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)

    https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...

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

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

  8. bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并)

    bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并) bzoj Luogu 给出一个字符串 $ S $ 及 $ q $ 次询问,每次询问一个字符串 $ T $ ...

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

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

随机推荐

  1. Oracle之into

    ), NVL() INTO SALE_ID, STORE_ID FROM SALEFROMSTORE WHERE ORDERID = IN_ORDER_ID; 这里要注意,into的时候是一个sele ...

  2. Monitoring tools that everyone's currently using

    Although a lot of new tools have arrived since 2011, it's clear that older open source tools like Na ...

  3. NBU客户端备份失败,报错error 48 client hostname could not be found

    今天在做备份时发现了这个报错.经过ping, nslookup, bpclntcmd命令检查没有发现连接或域名解析存在问题. 参考文档http://www.symantec.com/docs/TECH ...

  4. 使用百度地图API进行坐标系转换

    最近在做移动APP的定位功能的时候发现系统GPS获取的位置信息再从百度地图API获取的实际地址总是有误差,偏离了好几个街道,但百度地图本身没这个问题.在网上查找一番发现了地图的坐标系一说,下面简单介绍 ...

  5. python爬虫(4)--Cookie的使用

    Cookie,指某些网站为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密) 比如说有些网站需要登录后才能访问某个页面,在登录之前,你想抓取某个页面内容是不允许的.那么 ...

  6. myeclipse.ini

    myeclipse10 32位 我的配置 #utf8 (do not remove) #utf8 (do not remove) -startup ../Common/plugins/org.ecli ...

  7. ==, equals, hashcode的理解

    一.java对象的比较 等号(==): 对比对象实例的内存地址(也即对象实例的ID),来判断是否是同一对象实例:又可以说是判断对象实例是否物理相等: equals(): 对比两个对象实例是否相等. 当 ...

  8. 项目一:第十三天 1、菜单数据管理 2、权限数据管理 3、角色数据管理 4、用户数据管理 5、在realm中动态查询用户权限,角色 6、Shiro中整合ehcache缓存权限数据

    1 课程计划 菜单数据管理 权限数据管理 角色数据管理 用户数据管理 在realm中动态查询用户权限,角色 Shiro中整合ehcache缓存权限数据         2 菜单数据添加 2.1 使用c ...

  9. PCL—关键点检测(Harris)低层次点云处理

    博客转载自:http://www.cnblogs.com/ironstark/p/5064848.html 除去NARF这种和特征检测联系比较紧密的方法外,一般来说特征检测都会对曲率变化比较剧烈的点更 ...

  10. WOJ 41 约数统计

    只会写60分算法QuQ 考虑到一个数$x$大于$\sqrt{x}$的质因数最多只有一个,我们可以筛出小于$\sqrt{r}$范围内的所有质因数然后直接用这些取分解质因数. 最后扫一遍发现还没有分解完的 ...