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;
}

 

posted @ 2018-12-21 08:57  寒雨微凝  阅读(128)  评论(0编辑  收藏  举报