• 【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)


    【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)

    题面

    自从有了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
    ",min(A.Query(1,1,n,i),B.Query(1,1,n,i)-i));
    	return 0;
    }
    
    
    
  • 相关阅读:
    formValidator表单验证
    js中判断一个对象的类型的种种方法
    利用jQuery中的serialize方法大量获取页面中表单的数据,发送的服务器
    用html和css写一个头部header和左侧菜单栏menu-bar固定的的页面
    关于刚才那个全选问题的解决
    关于input[type='checkbox']全选的问题
    用CSS来定义<p>标签,要求实现以下效果:字体颜色再IE6下为黑色,IE7下为红色,IE8下为绿色,其他浏览器下为黄色。
    Vue.js(20)之 封装字母表(是这个名字吗0.0)
    Vue.js之calendar组件
    书:构造器模式
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8695350.html
Copyright © 2020-2023  润新知