• [BZOJ1396] 识别子串


    Description

    img

    Input

    一行,一个由小写字母组成的字符串S,长度不超过10^5

    Output

    L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.

    Solution

    建后缀自动机。

    对于每个(sz)(0)的点可以造成两段贡献,一段直线,一段斜率为(-1)的斜线。

    水平的线直接线段树维护就好了,斜率(-1)的可以那个数组记一下然后倒着枚举统计答案就好了,这步不是很好讲...可以看看代码中标记部分。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 2e5+10;
    const int inf = 1e9;
    
    char s[maxn];
    int cnt,lstp;
    int ml[maxn],par[maxn],pos[maxn],tr[maxn][26],sz[maxn],sum[maxn],rr[maxn];
    
    void append(int x,int i) {
    	int p=lstp,np=++cnt;pos[np]=i,ml[np]=ml[p]+1;sz[np]=1;lstp=np;
    	for(;p&&tr[p][x]==0;p=par[p]) tr[p][x]=np;
    	if(!p) return par[np]=1,void();
    	int q=tr[p][x];
    	if(ml[p]+1<ml[q]) {
    		int nq=++cnt;ml[nq]=ml[p]+1;pos[nq]=pos[q];
    		memcpy(tr[nq],tr[q],sizeof tr[nq]);
    		par[nq]=par[q],par[q]=par[np]=nq;
    		for(;p&&tr[p][x]==q;p=par[p]) tr[p][x]=nq;
    	} else par[np]=q;
    }
    
    void prepare() {
    	for(int i=1;i<=cnt;i++) sum[ml[i]]++;
    	for(int i=1;i<=cnt;i++) sum[i]+=sum[i-1];
    	for(int i=1;i<=cnt;i++) rr[sum[ml[i]]--]=i;
    
    	for(int i=cnt;i;i--) sz[par[rr[i]]]+=sz[rr[i]];
    }
    
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    
    int tag[maxn<<1],t[maxn<<1],ns[maxn],ans[maxn];
    
    void push_tag(int p,int v) {t[p]=min(t[p],v),tag[p]=min(tag[p],v);}
    void pushdown(int p) {if(tag[p]!=inf) push_tag(ls,tag[p]),push_tag(rs,tag[p]),tag[p]=inf;}
    
    void build(int p,int l,int r) {
    	t[p]=tag[p]=inf;
    	if(l==r) return ;
    	build(ls,l,mid),build(rs,mid+1,r);
    }
    
    void modify(int p,int l,int r,int x,int y,int v) {
    	if(x<=l&&r<=y) return push_tag(p,v),void();
    	pushdown(p);
    	if(x<=mid) modify(ls,l,mid,x,y,v);
    	if(y>mid) modify(rs,mid+1,r,x,y,v);
    }
    
    void dfs(int p,int l,int r) {
    	if(l==r) return ans[l]=t[p],void();
    	pushdown(p);dfs(ls,l,mid),dfs(rs,mid+1,r);
    }
    
    int main() {
    	scanf("%s",s+1);int n=strlen(s+1);cnt=lstp=1;
    	for(int i=1;i<=n;i++) append(s[i]-'a',i);
    	build(1,1,n);prepare();
    	for(int i=1;i<=n;i++) ns[i]=inf;
    	for(int i=1;i<=cnt;i++) {
    		if(sz[i]!=1) continue;
    		int l=pos[i]-ml[i]+1,r=pos[i]-ml[par[i]];
    		if(l!=r) ns[r-1]=min(ns[r-1],pos[i]-r+2);
    		modify(1,1,n,r,pos[i],ml[par[i]]+1);
    	}
    	dfs(1,1,n);int p=inf;
    	for(int i=n;i;i--) p=min(p+1,ns[i]),ans[i]=min(ans[i],p);   //slope -1 solved here
    	for(int i=1;i<=n;i++) write(ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    chrome安装插件
    如何在JIRA中有效使用关注和@提及 我正在关注的问题 提及我的问题 在仪表板上显示
    SQL Server中查找包含某个文本的存储过程 SQL 查找存储过程中出现过的文字怎么查询 查询整个数据库中出现的文本 sql 全局搜索
    Postman中添加真实请求(Chrome Networks中的全部请求,含https)copy as har
    SCOPE_IDENTITY 和 @@IDENTITY
    The underlying connection was closed: An unexpected error occurred on a rece
    mybatis中参数为list集合时使用 mybatis in查询
    如何在Mybatis的xml文件调用java类的方法
    Java中List, Integer[], int[]的相互转换
    ASP .NET Core HTTP Error 502.5 – Process Failure
  • 原文地址:https://www.cnblogs.com/hbyer/p/10523474.html
Copyright © 2020-2023  润新知