zoukankan      html  css  js  c++  java
  • bzoj 1396: 识别子串 && bzoj 2865: 字符串识别【后缀数组+线段树】

    根据height数组的定义,和当前后缀串i最长的相同串的长度就是max(height[i],height[i+1]),这个后缀贡献的最短不同串长度就是len=max(height[i],height[i+1])
    考虑这个贡献的范围,对于ii+len,贡献是len,对于w=i+len+1n可以更新w-len+1,也就是这长为len的串再向右延伸,可以证明这也是不重子串
    这两个东西用两个线段树维护,w-len+1这个直接把-len+1打在线段树上,查询的时候再加回w即可

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=500005;
    int n,wa[N],wb[N],wv[N],wsu[N],sa[N],rk[N],he[N];
    char s[N];
    struct qwe
    {
    	int l,r,mn[2],lz[2];
    }t[N<<2];
    bool cmp(int r[],int a,int b,int l)
    {
    	return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    void saa(char r[],int n,int m)
    {
    	int *x=wa,*y=wb;
    	for(int i=0;i<=m;i++)
    		wsu[i]=0;
    	for(int i=1;i<=n;i++)
    		wsu[x[i]=r[i]]++;
    	for(int i=1;i<=m;i++)
    		wsu[i]+=wsu[i-1];
    	for(int i=n;i>=1;i--)
    		sa[wsu[x[i]]--]=i;
    	for(int j=1,p=1;j<=n&&p<n;j<<=1,m=p)
    	{
    		p=0;
    		for(int i=n-j+1;i<=n;i++)
    			y[++p]=i;
    		for(int i=1;i<=n;i++)
    			if(sa[i]>j)
    				y[++p]=sa[i]-j;
    		for(int i=1;i<=n;i++)
    			wv[i]=x[y[i]];
    		for(int i=0;i<=m;i++)
    			wsu[i]=0;
    		for(int i=1;i<=n;i++)
    			wsu[wv[i]]++;
    		for(int i=1;i<=m;i++)
    			wsu[i]+=wsu[i-1];
    		for(int i=n;i>=1;i--)
    			sa[wsu[wv[i]]--]=y[i];
    		swap(x,y);
    		x[sa[1]]=1;
    		p=1;
    		for(int i=2;i<=n;i++)
    			x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p:++p;
    	}
    	for(int i=1;i<=n;i++)
    		rk[sa[i]]=i;
    	for(int i=1,j,k=0;i<=n;he[rk[i++]]=k)
    		for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
    }
    void pd(int w,int ro)
    {
    	if(t[ro].lz[w]!=1e9)
    	{
    		t[ro<<1].lz[w]=min(t[ro<<1].lz[w],t[ro].lz[w]);
    		t[ro<<1].mn[w]=min(t[ro<<1].mn[w],t[ro].lz[w]);
    		t[ro<<1|1].lz[w]=min(t[ro<<1|1].lz[w],t[ro].lz[w]);
    		t[ro<<1|1].mn[w]=min(t[ro<<1|1].mn[w],t[ro].lz[w]);
    		t[ro].lz[w]=1e9;
    	}
    }
    void build(int ro,int l,int r)
    {
    	t[ro].l=l,t[ro].r=r;
    	t[ro].mn[0]=t[ro].mn[1]=1e9;
    	t[ro].lz[0]=t[ro].lz[1]=1e9;
    	if(l==r)
    		return;
    	int mid=(l+r)>>1;
    	build(ro<<1,l,mid);
    	build(ro<<1|1,mid+1,r);
    }
    void update(int w,int ro,int l,int r,int v)
    {
    	if(t[ro].l==l&&t[ro].r==r)
    	{
    		t[ro].lz[w]=min(t[ro].lz[w],v);
    		t[ro].mn[w]=min(t[ro].mn[w],v);
    		return;
    	}
    	pd(w,ro);
    	int mid=(t[ro].l+t[ro].r)>>1;
    	if(r<=mid)
    		update(w,ro<<1,l,r,v);
    	else if(l>mid)
    		update(w,ro<<1|1,l,r,v);
    	else
    		update(w,ro<<1,l,mid,v),update(w,ro<<1|1,mid+1,r,v);
    	t[ro].mn[w]=min(t[ro<<1].mn[w],t[ro<<1|1].mn[w]);
    }
    int ques(int ro,int p)
    {
    	if(t[ro].l==t[ro].r)
    		return min(t[ro].mn[0],t[ro].mn[1]+p);
    	pd(0,ro);
    	pd(1,ro);
    	int mid=(t[ro].l+t[ro].r)>>1;
    	if(p<=mid)
    		return ques(ro<<1,p);
    	else
    		return ques(ro<<1|1,p);
    }
    int main()
    {
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	saa(s,n,200);
    	build(1,1,n);
    	for(int i=1;i<=n;i++)
    	{
    		int len=max(he[rk[i]],he[rk[i]+1]);
    		if(i+len<=n)
    			update(0,1,i,i+len,len+1);
    		if(i+len<n)
    			update(1,1,i+len+1,n,1-i);
    	}
    	for(int i=1;i<=n;i++)
    		printf("%d
    ",ques(1,i));
    	return 0;
    }
    
  • 相关阅读:
    洛谷
    洛谷
    洛谷
    模板
    洛谷
    洛谷
    Codeforces Round #561 (Div. 2) E. The LCMs Must be Large(数学)
    Codeforces Round #561 (Div. 2)
    Mail.Ru Cup 2018 Round 2 C. Lucky Days(拓展欧几里得)
    The 10th Shandong Provincial Collegiate Programming Contest H.Tokens on the Segments(贪心+优先级队列 or 贪心+暴力)
  • 原文地址:https://www.cnblogs.com/lokiii/p/9696906.html
Copyright © 2011-2022 走看看