zoukankan      html  css  js  c++  java
  • 【BZOJ1396】—识别子串(后缀自动机+线段树)

    传送门


    显然只出现一次的节点就是SamSamfailfail树的叶子节点

    考虑对于一个叶子节点uu和父亲vv
    对于i[len[u]len[v]]iin[len[u]-len[v]],答案可能是len[v]+1len[v]+1
    对于i[1,len[u]len[v]1],len[u]i+1iin[1,len[u]-len[v]-1],答案可能是len[u]-i+1

    建2颗线段树分别维护len[u]+1len[u]+1len[v]+1len[v]+1的最小值即可

    #include<bits/stdc++.h>
    using namespace std;
    #define gc getchar
    inline int read(){
    	char ch=gc();
    	int res=0,f=1;
    	while(!isdigit(ch))f^=ch=='-',ch=gc();
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    	return f?res:-res;
    }
    #define ll long long
    #define pb push_back
    #define pii pair<int,int>
    #define fi first
    #define se second
    const int N=100005;
    const int inf=1e9;
    struct Seg{
    	int tr[N<<2],tag[N<<2],a[N];
    	#define lc (u<<1)
    	#define rc ((u<<1)|1)
    	#define mid ((l+r)>>1)
    	inline void pushup(int u){
    		tr[u]=min(tr[lc],tr[rc]);
    	}
    	inline void pushnow(int u,int k){
    		if(k<tr[u])tr[u]=k;
    		if(!tag[u])tag[u]=k;
    		else if(k<tag[u])tag[u]=k;
    	}
    	inline void pushdown(int u){
    		if(tag[u]==0)return;
    		pushnow(lc,tag[u]),pushnow(rc,tag[u]);
    		tag[u]=0;
    	}
    	inline void build(int u,int l,int r){
    		tr[u]=inf;
    		if(l==r)return;
    		build(lc,l,mid),build(rc,mid+1,r);
    	}
    	inline void update(int u,int l,int r,int st,int des,int k){
    		if(st<=l&&r<=des){pushnow(u,k);return;}
    		pushdown(u);
    		if(st<=mid)update(lc,l,mid,st,des,k);
    		if(mid<des)update(rc,mid+1,r,st,des,k);
    		pushup(u);
    	}
    	inline void query(int u,int l,int r){
    		if(l==r){a[l]=tr[u];return;}
    		pushdown(u);
    		query(lc,l,mid),query(rc,mid+1,r);
    	}
    	#undef lc 
    	#undef rc
    	#undef mid
    }t1,t2;
    char s[N];
    int n;
    namespace Sam{
    	int fa[N<<1],len[N<<1];
    	map<int,int>nxt[N<<1];
    	int last,tot;
    	inline void insert(int c){
    		int cur=++tot,p=last;last=cur,len[cur]=len[p]+1;
    		for(;p&&!nxt[p][c];p=fa[p])nxt[p][c]=cur;
    		if(!p)fa[cur]=1;
    		else{
    			int q=nxt[p][c];
    			if(len[q]==len[p]+1)fa[cur]=q;
    			else{
    				int clo=++tot;
    				len[clo]=len[p]+1,fa[clo]=fa[q],nxt[clo]=nxt[q];
    				for(;p&&nxt[p][c]==q;p=fa[p])nxt[p][c]=clo;
    				fa[q]=fa[cur]=clo;
    			}
    		}
    	}
    	int isl[N<<1];
    	inline void work(){
    		t1.build(1,1,n),t2.build(1,1,n);
    		for(int i=1;i<=tot;i++)isl[fa[i]]=1;
    		for(int i=1;i<=tot;i++){
    			if(!isl[i]){
    				int l=len[i]-len[fa[i]],r=len[i];
    				t1.update(1,1,n,l,r,len[fa[i]]+1);
    				if(l!=1)t2.update(1,1,n,1,l-1,r+1);
    			}
    		}
    		t1.query(1,1,n),t2.query(1,1,n);
    		for(int i=1;i<=n;i++)
    			cout<<min(t1.a[i],t2.a[i]-i)<<'
    ';
    	}
    }
    int main(){
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	Sam::last=Sam::tot=1;
    	for(int i=1;i<=n;i++)Sam::insert(s[i]-'a');
    	Sam::work();
    }
    
  • 相关阅读:
    Google Earth 使用的经纬度格式及转换
    ADO.NET Entity Framework 一个简单数据绑定例子
    Oracle 异常 ORA01861: literal does not match format string(字符串格式不匹配)
    备份和还原 甲方 Oracle 数据库 问题一大堆
    使用 xsd.exe 命令工具 将 xsd架构 生成 类文件
    简单的源代码统计工具(统计源代码行数、工数、成本、质量指标统计)
    Google KML 起步教程笔记(二)高级 KML 文档与MIME 类型
    SQL Server 2008 中的空间数据存储
    PowerCmd 很好用的命令行工具,也许大家早就知道。
    Google Earth 本地地图缓存文件路径和KML文件路径
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328795.html
Copyright © 2011-2022 走看看