zoukankan      html  css  js  c++  java
  • BZOJ 2865 字符串识别(后缀数组+线段树)

    很容易想到只考虑后缀长度必须为(max(height[rk[i]],height[rk[i]+1])+1)(即([i,i+x-1])代表的串只出现过一次)然后我正着做一遍反着做一遍,再取一个(min)最后挂了。。。
    (x=max(height[rk[i]],height[rk[i]+1])+1)我们考虑(i)的贡献,会给区间([i,i+x-1])一个贡献x
    ,设(r=i+x-1)然后会给r+1一个贡献x+1就是(r+1)-i+1,接着是r+2的贡献(r+2)-i+1。。。
    最后我们对每一个点求出这个点的最小的贡献。这堆东西可以用线段树维护。
    值得注意的一点是当i+x-1>n时并不能产生贡献,因为此时已经到了字符串末尾。
    我们无法加上(max(height[rk[i]],height[rk[i]+1])+1)最后的那个1。

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define mid ((l+r)>>1)
    #define ls now<<1
    #define rs now<<1|1
    const int N=501000;
    int c[N],x[N],y[N],sa[N],rk[N],height[N],n,m;
    int lazy1[N*5],lazy2[N*5],mn[N*5];
    char s[N];
    void get_sa(){
    	for(int i=1;i<=n;i++)c[x[i]=s[i]]++;
    	for(int i=1;i<=m;i++)c[i]+=c[i-1];
    	for(int i=n;i>=1;i--)sa[c[x[i]]--]=i;
    	for(int k=1;k<=n;k<<=1){
    		int num=0;
    		for(int i=n-k+1;i<=n;i++)y[++num]=i;
    		for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
    		for(int i=1;i<=m;i++)c[i]=0;
    		for(int i=1;i<=n;i++)c[x[i]]++;
    		for(int i=1;i<=m;i++)c[i]+=c[i-1];
    		for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
    		for(int i=1;i<=n;i++)swap(x[i],y[i]);
    		x[sa[1]]=1;num=1;
    		for(int i=2;i<=n;i++)
    			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
    		if(n==num)break;
    		m=num;
    	}
    }
    void get_height(){
    	int k=0;
    	for(int i=1;i<=n;i++)rk[sa[i]]=i;
    	for(int i=1;i<=n;i++){
    		if(rk[i]==1)continue;
    		if(k)k--;
    		int j=sa[rk[i]-1];
    		while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
    		height[rk[i]]=k;
    	}
    }
    void build(int l,int r,int now){
    	if(l==r){mn[now]=n;return;}
    	build(l,mid,ls);
    	build(mid+1,r,rs);
    }
    void update(int now){
    	mn[now]=min(mn[ls],mn[rs]);
    }
    void pushdown(int l,int r,int now){
    	if(l==r)return;
    	if(lazy1[now]){
    		mn[ls]=min(mn[ls],lazy1[now]);
    		mn[rs]=min(mn[rs],lazy1[now]);
    		if(lazy1[rs])lazy1[rs]=min(lazy1[rs],lazy1[now]);
    		else lazy1[rs]=lazy1[now];
    		if(lazy1[ls])lazy1[ls]=min(lazy1[ls],lazy1[now]);
    		else lazy1[ls]=lazy1[now];
    		lazy1[now]=0;
    	}
    	if(lazy2[now]){
    		mn[ls]=min(mn[ls],l+lazy2[now]);
    		mn[rs]=min(mn[rs],mid+1+lazy2[now]);
    		if(lazy2[rs])lazy2[rs]=min(lazy2[rs],lazy2[now]);
    		else lazy2[rs]=lazy2[now];
    		if(lazy2[ls])lazy2[ls]=min(lazy2[ls],lazy2[now]);
    		else lazy2[ls]=lazy2[now];
    		lazy2[now]=0;
    	}
    }
    void add1(int l,int r,int L,int R,int w,int now){
    	pushdown(l,r,now);
    	if(l==L&&r==R){
    		lazy1[now]=w;
    		mn[now]=min(mn[now],w);
    		return;
    	}
    	if(L>mid)add1(mid+1,r,L,R,w,rs);
    	else if(R<=mid)add1(l,mid,L,R,w,ls);
    	else add1(l,mid,L,mid,w,ls),add1(mid+1,r,mid+1,R,w,rs);
    	update(now);
    }
    void add2(int l,int r,int L,int R,int w,int now){
    	if(L>R)return;
    	pushdown(l,r,now);
    	if(l==L&&r==R){
    		lazy2[now]=w;
    		mn[now]=min(l+w,mn[now]);
    		return;
    	}
    	if(L>mid)add2(mid+1,r,L,R,w,rs);
    	else if(R<=mid)add2(l,mid,L,R,w,ls);
    	else add2(l,mid,L,mid,w,ls),add2(mid+1,r,mid+1,R,w,rs);
    	update(now);
    }
    int check(int l,int r,int x,int now){
    	pushdown(l,r,now);
    	if(l==r)return mn[now];
    	if(x>mid)return check(mid+1,r,x,rs);
    	else return check(l,mid,x,ls);
    }
    int main(){
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	m=122;
    	get_sa();get_height();
    	build(1,n,1);
    	for(int i=1;i<=n;i++){
    		int tmp=max(height[rk[i]],height[rk[i]+1])+1;
    		if(i+tmp-1<=n)add1(1,n,i,i+tmp-1,tmp,1);
    		add2(1,n,i+tmp,n,-i+1,1);
    	}
    	for(int i=1;i<=n;i++)printf("%d
    ",check(1,n,i,1));
    	return 0; 
    }
    
  • 相关阅读:
    55最佳实践系列:Logging最佳实践
    关于 Multiget hole:spymemcached对此的实现方法
    Java两则故障分析和常见连接超时时间
    spymemcached :某个mc节点操作连续超时超过998次就 AutoReconnect 的特性
    最佳实践系列:前端代码标准和最佳实践
    随手小记:PHPFPM模式下PHP最大执行时间、Pragma和postcheck
    Storm 是如何跟踪一条消息以及它衍生出来的消息都被成功处理的
    Tumblr的消息通知系统是如何构建的
    职业化之可以固化的六个工作模式
    三个实例演示 Java Thread Dump 日志分析
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/10217174.html
Copyright © 2011-2022 走看看