【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)
2018-04-02 17:07
417 查看
题面
自从有了DBZOJ终于有地方交权限题了
题解
很明显,只出现了一次的串在SAM的right/endpos集合大小一定为1
换句话说,在parent树上是叶子节点
找到所有这样的节点,
假设它的len=r,它父亲的len=p,它的结束位置为显然就是r
令l=r−p
以r结尾,
并且只出现了一次的串的左端点
为1..l,那么,他们的答案可以更新为r+1−i
剩下的位置l+1..r,他们无法作为左端点,只能包含在这些串中
于是找到一个最短的包含他们的串S[l..r]
所以,这段区间的答案可以更新为r−l+1
显然不好一起维护,
于是开两棵线段树,一个维护r+1−i,先不考虑i,最后减去就好
另一个直接维护r−l+1
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define lson (now<<1) #define rson (now<<1|1) #define MAX 111111 inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } int n; bool vis[MAX<<1]; struct SAM { struct Node { int son[26]; int ff,len; }t[MAX<<1]; int last,tot; void init(){last=tot=1;} void extend(int c) { int p=last,np=++tot;last=np; t[np].len=t[p].len+1; while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff; if(!p)t[np].ff=1; else { int q=t[p].son[c]; if(t[q].len==t[p].len+1)t[np].ff=q; else { int nq=++tot; t[nq]=t[q];t[nq].len=t[p].len+1; t[np].ff=t[q].ff=nq; while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff; } } } }SAM; char ch[MAX]; struct SegMentTree { struct Node{int v;}t[MAX<<2]; void Build(int now,int l,int r) { t[now].v=1e9;if(l==r)return; int mid=(l+r)>>1; Build(lson,l,mid);Build(rson,mid+1,r); } void puttag(int now,int w){t[now].v=min(t[now].v,w);} void pushdown(int now) { if(t[now].v==1e9)return; puttag(lson,t[now].v);puttag(rson,t[now].v); t[now].v=1e9; } void Modify(int now,int l,int r,int L,int R,int w) { if(L>R)return; if(L<=l&&r<=R){puttag(now,w);return;} pushdown(now);int mid=(l+r)>>1; if(L<=mid)Modify(lson,l,mid,L,R,w); if(R>mid)Modify(rson,mid+1,r,L,R,w); } int Query(int now,int l,int r,int p) { if(l==r)return t[now].v; pushdown(now);int mid=(l+r)>>1; if(p<=mid)return Query(lson,l,mid,p); else return Query(rson,mid+1,r,p); } }A,B; int main() { SAM.init(); scanf("%s",ch+1);n=strlen(ch+1); for(int i=1;i<=n;++i)SAM.extend(ch[i]-97); for(int i=1;i<=SAM.tot;++i)vis[SAM.t[i].ff]=true; A.Build(1,1,n);B.Build(1,1,n); for(int i=1;i<=SAM.tot;++i) if(!vis[i]) { int l=SAM.t[i].len-SAM.t[SAM.t[i].ff].len,r=SAM.t[i].len; A.Modify(1,1,n,l,r,r-l+1); B.Modify(1,1,n,1,l-1,r+1); } for(int i=1;i<=n;++i) printf("%d\n",min(A.Query(1,1,n,i),B.Query(1,1,n,i)-i)); return 0; }
相关文章推荐
- [后缀自动机 线段树] BZOJ 1396 识别子串 & BZOJ 2865 字符串识别
- 【BZOJ-1396&2865】识别子串&字符串识别 后缀自动机/后缀树组 + 线段树
- 【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)
- BZOJ 1396&&2865 识别子串[后缀自动机 线段树]
- BZOJ1396&2865 识别子串 【后缀自动机 + 线段树】
- bzoj 1396: 识别子串 && bzoj 2865: 字符串识别【后缀数组+线段树】
- [BZOJ2865]字符串识别 后缀自动机+线段树
- [BZOJ1396]识别子串(后缀自动机+线段树)
- 【bzoj2865】字符串识别 后缀自动机+线段树
- bzoj 1396: 识别子串 (后缀自动机+线段树)
- [BZOJ1396]识别子串 后缀自动机+线段树
- BZOJ1396:识别子串(后缀自动机+单调队列)
- BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)
- BZOJ 1396: 识别子串( 后缀数组 + 线段树 )
- bzoj 3277: 串 & bzoj 3473: 字符串【后缀自动机||后缀数组】
- [广义后缀自动机] BZOJ 3473 字符串 & BZOJ 3277 串 & Codeforces 204E #129 (Div. 1) E. Little Elephant and Strings
- BZOJ 2865 字符串识别 | 后缀数组 线段树
- bzoj 3473 后缀自动机多字符串的子串处理方法
- BZOJ 3473 字符串 ——广义后缀自动机
- [BZOJ2946][Poi2000]公共串 && 后缀自动机