1396: 识别子串

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 312  Solved: 193
[Submit][Status][Discuss]

Description

Input

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

Output

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

Sample Input

agoodcookcooksgoodfood

Sample Output

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

HINT

Source

Solution

BZOJ:1396

这题使用 后缀自动机+线段树 的做法;

首先按照这道题的要求,所有的识别子串一定是$|Right|=1$的节点所代表的子串之一,问题在于统计最短。

这样可以考虑再记录每个$Right$集合的最后一个$endpos$,然后利用这个去考虑对原串每个位置的贡献。

对于$[endpos-maxlen+1,endpos-minlen+1]$中的每个位置$x$,贡献就是$endpos-x+1$;

理解起来就是对于$[endpos-maxlen+1,endpos-minlen+1]$中的每个子串都是单独存在的,所以这个$Right$集合贡献给他的答案就是这个点到$endpos$的长度。

对于$[endpos-minlen,endpos]$中的每个位置$x$,贡献就是$minlen$;

理解起来就是对于$[endpos-minlen,endpos]$中的每个子串显然是存在多个结束位置的,所以当前这个$Right$集合能够贡献给他的符合只出现一次且最短的,就是刚好跨过它的最小,即$minlen$。

这样对于两种情况,分别用线段树去维护,至于第一种情况的$-x$是定值,所以拿到外面比较的时候再算进答案即可。

BZOJ2865

这道题和上道题完全一样,不过数据范围扩大了,需要卡内存...用上了map内存还是多10M...于是直接写 后缀树组+线段树 的做法了。

和刚刚的想法类似。

考虑固定左端点$l$,对后面的影响。

容易发现,固定了$l$之后,对后面的答案,存在两种影响。

设这样两种情况的分界点为$m$

对于第一种影响$[l,m]$贡献的答案就是$lcp+1$,而第二种$[m+1,N]$的每个位置$x$贡献答案就是$x-l+1$

所以这样可以枚举$sa_{i}$,对于$sa_{i}$它的$lcp+1$实际上就是与它相邻的两个后缀的$height_{max}+1$,那么分界点$m$恰好是$sa_{i}+lcp$.

理解起来就是对于它的$lcp$显然是重复出现过的,那么这段的答案最短就是$lcp+1$,而对于这段之后的位置的影响,显然就是 那个位置到当前位置$sa_{i}$的距离长度的串 最短。

用同样的方法用两棵线段树维护.

Code

BZOJ1396

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define MAXN 100010
#define INF 0x7fffffff
char S[MAXN];
int N;
namespace SegmentTree{
#define lson now<<1
#define rson now<<1|1struct SgtNode{int l,r,minn,tag;};struct SegmentTree{SgtNode tree[MAXN<<2];inline void Update(int now) {tree[now].minn=min(tree[lson].minn,tree[rson].minn);}inline void Build(int now,int l,int r){tree[now].tag=tree[now].minn=INF;tree[now].l=l,tree[now].r=r;if (l==r) return;int mid=(l+r)>>1;Build(lson,l,mid); Build(rson,mid+1,r);}inline void Pushdown(int now){if (tree[now].l==tree[now].r || tree[now].tag==INF) return;int val=tree[now].tag; tree[now].tag=INF;tree[lson].minn=min(tree[lson].minn,val);tree[rson].minn=min(tree[rson].minn,val);tree[lson].tag=min(tree[lson].tag,val);tree[rson].tag=min(tree[rson].tag,val);}inline void Modify(int now,int L,int R,int val){if (L>R) return;int l=tree[now].l,r=tree[now].r;Pushdown(now);if (L<=l && R>=r) {tree[now].tag=min(tree[now].tag,val);tree[now].minn=min(tree[now].minn,val);return;}int mid=(l+r)>>1;if (L<=mid) Modify(lson,L,R,val);if (R>mid) Modify(rson,L,R,val);Update(now);}inline int Query(int now,int pos){int l=tree[now].l,r=tree[now].r;Pushdown(now);if (l==r) return tree[now].minn;int mid=(l+r)>>1;if (pos<=mid) return Query(lson,pos);else return Query(rson,pos);}}t1,t2;
}using namespace SegmentTree;namespace SAM{int son[MAXN<<1][27],len[MAXN<<1],par[MAXN<<1],endpos[MAXN<<1],size[MAXN<<1];int last,root,sz;inline void init() {last=root=++sz;}inline void Extend(int c,int pos){int cur=++sz,p=last;len[cur]=len[p]+1; endpos[cur]=pos; size[cur]=1;while (p && !son[p][c]) son[p][c]=cur,p=par[p];if (!p) par[cur]=root;else {int q=son[p][c];if (len[p]+1==len[q]) par[cur]=q;else {int nq=++sz;memcpy(son[nq],son[q],sizeof(son[nq]));len[nq]=len[p]+1; par[nq]=par[q];while (p && son[p][c]==q) son[p][c]=nq,p=par[p];par[q]=par[cur]=nq;     }}last=cur;}inline void Build() {init(); for (int i=1; i<=N; i++) Extend(S[i]-'a'+1,i);}int st[MAXN],id[MAXN<<1];inline void Prework(){for (int i=1; i<=sz; i++) st[len[i]]++;for (int i=1; i<=N; i++) st[i]+=st[i-1];for (int i=1; i<=sz; i++) id[st[len[i]]--]=i;for (int i=sz; i>=1; i--) {int x=id[i];size[par[x]]+=size[x];endpos[par[x]]=max(endpos[par[x]],endpos[x]);}}inline void Work(){for (int i=1; i<=sz; i++)if (size[i]==1) {int maxlen=len[i],minlen=len[par[i]]+1,end=endpos[i];
//              printf("%d  %d  %d\n",end,maxlen,minlen);t1.Modify(1,end-maxlen+1,end-minlen+1,end+1);t2.Modify(1,end-minlen+1,end,minlen);}for (int i=1; i<=N; i++) {int x=t1.Query(1,i)-i,y=t2.Query(1,i);printf("%d\n",min(x,y));}}
}using namespace SAM;
int main()
{scanf("%s",S+1); N=strlen(S+1);t1.Build(1,1,N),t2.Build(1,1,N);SAM::Build();SAM::Prework();SAM::Work();return 0;
}

BZOJ2865

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
#define MAXN 500010
char S[MAXN];
int N;
#define INF 0x3fffffff
namespace SegmentTree{
#define lson now<<1
#define rson now<<1|1struct SgtNode{int l,r,minn,tag;};struct SegmentTree{SgtNode tree[MAXN<<2];inline void Update(int now) {tree[now].minn=min(tree[lson].minn,tree[rson].minn);}inline void Build(int now,int l,int r){tree[now].tag=tree[now].minn=INF;tree[now].l=l,tree[now].r=r;if (l==r) return;int mid=(l+r)>>1;Build(lson,l,mid); Build(rson,mid+1,r);}inline void Pushdown(int now){if (tree[now].l==tree[now].r || tree[now].tag==INF) return;int val=tree[now].tag; tree[now].tag=INF;tree[lson].minn=min(tree[lson].minn,val);tree[rson].minn=min(tree[rson].minn,val);tree[lson].tag=min(tree[lson].tag,val);tree[rson].tag=min(tree[rson].tag,val);}inline void Modify(int now,int L,int R,int val){if (L>R) return;int l=tree[now].l,r=tree[now].r;Pushdown(now);if (L<=l && R>=r) {tree[now].tag=min(tree[now].tag,val);tree[now].minn=min(tree[now].minn,val);return;}int mid=(l+r)>>1;if (L<=mid) Modify(lson,L,R,val);if (R>mid) Modify(rson,L,R,val);Update(now);}inline int Query(int now,int pos){int l=tree[now].l,r=tree[now].r;Pushdown(now);if (l==r) return tree[now].minn;int mid=(l+r)>>1;if (pos<=mid) return Query(lson,pos);else return Query(rson,pos);}}t1,t2;
}using namespace SegmentTree;namespace SA{int r[MAXN],sa[MAXN],rank[MAXN],height[MAXN],st[MAXN],tx[MAXN],ty[MAXN];inline void Sort(int *x,int *y,int *sa,int L,int M){for (int i=0; i<=M; i++) st[i]=0;for (int i=0; i<L; i++) st[x[y[i]]]++;for (int i=1; i<=M; i++) st[i]+=st[i-1];for (int i=L-1; i>=0; i--) sa[--st[x[y[i]]]]=y[i]; }inline void DA(int *r,int *sa,int L,int M){int *x=tx,*y=ty,*t,i,j,p;for (int i=0; i<L; i++) x[i]=r[i],y[i]=i;Sort(x,y,sa,L,M);for (j=1,p=1; j<L && p<L; j<<=1,M=p-1) {for (p=0,i=L-j; i<L; i++) y[p++]=i;for (i=0; i<=L; i++) if (sa[i]>=j) y[p++]=sa[i]-j;Sort(x,y,sa,L,M);for (t=x,x=y,y=t,x[sa[0]]=0,i=1,p=1; i<L; i++)x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+j]==y[sa[i-1]+j]? p-1:p++;}}inline void Height(int *r,int *sa,int *rank,int *h,int L){h[1]=0;for (int i=1; i<=L; i++) rank[sa[i]]=i;for (int i=1,j,k=0; i<=L; h[rank[i++]]=k)for (k? k--:k=0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);}
}using namespace SA;int main()
{scanf("%s",S+1); N=strlen(S+1);for (int i=1; i<=N; i++) r[i]=S[i]-'a'+1;SA::DA(r,sa,N+1,27);SA::Height(r,sa,rank,height,N);//  for (int i=1; i<=N; i++) printf("%d ",sa[i]); puts("");
//  for (int i=1; i<=N; i++) printf("%d ",height[i]); puts("");t1.Build(1,1,N); t2.Build(1,1,N);for (int i=1; i<=N; i++) {int j=max(height[i],height[i+1])+1;if (j+sa[i]-1<=N) t1.Modify(1,sa[i],sa[i]+j-1,j);t2.Modify(1,sa[i]+j,N,1-sa[i]);
//      printf("%d    %d    %d    %d\n",i,j,sa[i],j+sa[i]); }for (int i=1; i<=N; i++) {int x=t1.Query(1,i),y=t2.Query(1,i)+i;printf("%d\n",min(x,y));}return 0;
}

自己断断续续想了好久才想到...真的是弱的没救了....

转载于:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6284980.html

【BZOJ-13962865】识别子串字符串识别 后缀自动机/后缀树组 + 线段树相关推荐

  1. HDU - 4416 Good Article Good sentence(广义后缀自动机/后缀自动机)

    题目链接:点击查看 题目大意:给出一个字符串 s ,再给出 n 个字符串 t ,现在问字符串 s 中有多少个不同的子串满足不是 t1 ~ tn 中任意一个字符串的子串 题目分析:第一次接触这样的题目, ...

  2. 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree...

    原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...

  3. BZOJ 1920 Luogu P4217 [CTSC2010]产品销售 (模拟费用流、线段树)

    题目链接 (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=1920 (luogu) https://www.luogu.org/prob ...

  4. BZOJ 3836 Codeforces 280D k-Maximum Subsequence Sum (模拟费用流、线段树)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=3836 (Codeforces) http://codeforces.com ...

  5. 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树

    题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...

  6. bzoj 2588 Spoj 10628. Count on a tree (可持久化线段树)

    Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MB Submit: 7669  Solved: 1894 [Sub ...

  7. BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)

    题目描述 Bob有一棵 nn 个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob ...

  8. BZOJ 1852 [MexicoOI06]最长不下降序列(贪心+DP+线段树+离散化)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1852 [题目大意] 给你N对数A1,B1--An,Bn.要求你从中找出最多的对, 把它 ...

  9. 【BZOJ】1672: [Usaco2005 Dec]Cleaning Shifts 清理牛棚(dp/线段树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1672 dp很好想,但是是n^2的..但是可以水过..(5s啊..) 按左端点排序后 f[i]表示取第 ...

最新文章

  1. [Hibernate]在VS2010中应用NHibernate 3.2与MySQL
  2. HDOJ 1224 Free DIY Tour
  3. RuoYi 若依框架整改
  4. pytorch 正向与反向传播的过程 获取模型的梯度(gradient),并绘制梯度的直方图
  5. jsp mysql 连接池_Tomcat下JSP连接mysql连接池
  6. phpfpm内存越来越高_DDR5内存规范发布
  7. 本地源制作docker镜像
  8. 如何在Ubuntu18.4中设置ERPNEXT开源ERP生产环境开机运行
  9. token干什么用_什么是TOKEN?Token小号的理解运用,拼多多,知乎,快手,抖音的Token是什么意思...
  10. 软件测试的容错性测试方法,你真的了解容错性测试吗?
  11. 如果批评《说好不哭》不自由,则赞美周杰伦无意义
  12. Fredman构造法构造完备哈希
  13. Pycharm安装、使用的一些操作
  14. 北理工计算机组成原理在线作业,[北京师范大学]20秋《计算机组成原理》离线作业...
  15. 自定义vue3.0日历组件
  16. 亚马逊封号,新规则来了,你知道了吗?
  17. SCI回复审稿意见的模板
  18. 南天收藏库为什么大不了_参加技术会议:有什么大不了的?
  19. CDH6 安装 Apache atlas
  20. ECharts 修改背景格子线条的颜色

热门文章

  1. myeclipse如何修改tomcat的timeout
  2. 七月在线数据结构视频教程一
  3. shell实例第19讲:一个脚本中调用另一个脚本的3种方法
  4. 用EXCEL实现时间戳格式和日期格互转
  5. swift的可选值(optional)
  6. 实现简单的网页间的跳转
  7. 激光投影市场将保持产品多元化发展趋势
  8. iOS 版 Skype支持群组语音聊天
  9. javaweb回顾第二篇tomcat和web程序部署
  10. 20161102学习笔记