BZOJ1396 识别子串
传送门
拼命给自己拉低AC率(
SAM 一发入魂
很明显 我们要查的就是 叶子结点
叶子结点 的 len 和 其父亲的 len 会影响一段区间
大概长这个样子 前面一段倾斜的 就是 len 在不断增长 后面的要取min所以就是平直的[你可能需要意会一下]
因为一个点的len是一段连续的区间 你从这个图里就可以看的比较清楚了qwq
然后我们 就重锤李超树 咳咳咳才不要李超树呢 我们发现 所有的斜线都是斜率为-1 那么我们对于斜线维护 ai+i 最后-i 就变成了直线
现在就是两种直线 我们分别用两棵线段树维护就好了
(注意:SAM中叶子节点一定是 “关键节点”[前缀节点] 而“关键节点”不一定全部都是叶子结点)
附代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 20021225
#define ll long long
#define mxn 100010
#define ls(x) x<<1
#define rs(x) x<<1|1
using namespace std;
int ans[mxn];
struct segtree
{
int mn[mxn*4],tag[mxn*4];
void pushdown(int x)
{
if(tag[x]<inf)
{
int tmp=tag[x];
mn[ls(x)] = min(mn[ls(x)],tmp);
mn[rs(x)] = min(mn[rs(x)],tmp);
tag[ls(x)] = min(tag[ls(x)],tmp);
tag[rs(x)] = min(tag[rs(x)],tmp);
tag[x]=inf;
}
}
void pushup(int x)
{
mn[x]=min(mn[ls(x)],mn[rs(x)]);
}
void build(int x,int l,int r)
{
mn[x] = tag[x] = inf;
if(l==r) return;
int mid = l+r>>1;
build(ls(x),l,mid);build(rs(x),mid+1,r);
}
void modify(int x,int l,int r,int LL,int RR,int val)
{
if(RR<LL) return;
if(l>=LL&&r<=RR)
{
mn[x] = min(mn[x],val);
tag[x] = min(tag[x],val);
return;
}
int mid=l+r>>1; pushdown(x);
if(LL<=mid) modify(ls(x),l,mid,LL,RR,val);
if(RR>mid) modify(rs(x),mid+1,r,LL,RR,val);
pushup(x);
}
void query(int x,int l,int r)
{
if(l==r){ans[l]=mn[x];return;}
int mid = l+r>>1; pushdown(x);
query(ls(x),l,mid); query(rs(x),mid+1,r);
}
}t1,t2;
struct node{int fa,len,ch[26];}t[mxn*4];
int poi,rt,lt; char ch[mxn];
int pos[mxn],n;
void init()
{
rt=lt=++poi;
t1.build(1,1,n);
t2.build(1,1,n);
}
int id(char c){return c-'a';}
bool vis[mxn*4];
void insert(int c,int id)
{
int p=lt,np=lt=++poi; t[np].len=t[p].len+1; pos[id]=np;
for(;p&&!t[p].ch[c];p=t[p].fa) t[p].ch[c]=np;
if(!p){t[np].fa=rt;return;}
int q=t[p].ch[c];
if(t[q].len==t[p].len+1){t[np].fa=q; vis[q] =1;return;}
int nq=++poi; t[nq].len=t[p].len+1;
memcpy(t[nq].ch,t[q].ch,sizeof(t[q].ch));
t[nq].fa=t[q].fa; t[q].fa=t[np].fa=nq; vis[nq] = 1;
for(;p&&t[p].ch[c]==q;p=t[p].fa) t[p].ch[c]=nq;
}
int f[mxn];
void calc()
{
for(int i=1;i<=n;i++)
{
int x=pos[i],f=t[x].fa;
if(vis[x]) continue;
int l2=t[x].len,l1=t[f].len+1;
t1.modify(1,1,n,i-l1+1,i,l1);
t2.modify(1,1,n,i-l2+1,i-l1,i+1);
}
t1.query(1,1,n); memcpy(f,ans,sizeof(f));
//for(int i=1;i<=n;i++) printf("%d ",ans[i]);
t2.query(1,1,n);
for(int i=1;i<=n;i++)
ans[i]-=i,f[i]=min(f[i],ans[i]);
for(int i=1;i<=n;i++)
printf("%d\n",f[i]);
}
int main()
{
scanf("%s",ch+1); n=strlen(ch+1); init();
for(int i=1;i<=n;i++) insert(id(ch[i]),i); calc();
return 0;
}