zoukankan      html  css  js  c++  java
  • BZOJ1396 识别子串

    传送门

    题目大意

    给定一个字符串,求对于每一个位置,求包含它的只出现一次的子串的最短长度。

    题解

    先建后缀自动机,对于每一个$|Endpos|=1$的节点,设其右端点为$r$。

    对于所有$xin [r-minlen+1,r]$,可以用$minlen$的长度更新答案。

    对于所有$xin [r-maxlen+1,r-minlen]$,可以用$r-x$的长度更新。

    用线段树维护两个标记,一个用来更新能够覆盖答案的最小长度$minlen$,即情况一,另一个用来更新能够用来更新答案的最左的右端点$r$,即情况二。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define M 200020
    using namespace std;
    namespace IO{
    	const int BS=(1<<20); int Top=0;
    	char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
    	char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return *HD++;}
    	void flush(){fwrite(OT,1,OS-OT,stdout);}
    	void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;}
    	void write(int x){
    		if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-');
    		while(x) SS[++Top]=x%10,x/=10;
    		while(Top) Putchar(SS[Top]+'0'),--Top; Putchar('
    ');
    	}
    	int read(){
    		int nm=0,fh=1; char cw=Getchar();
    		for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
    		for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
    		return nm*fh;
    	}
    }
    using namespace IO;
    char S[M]; int n;
    namespace segtree{
    	int tg[M<<1][2];
    	void init(){memset(tg,0x3f,sizeof(tg));}
    	void mdf(int x,int l,int r,int L,int R,int dt,int kd){
    		if(L<=l&&r<=R){tg[x][kd]=min(dt,tg[x][kd]);return;}
    		if(r<L||R<l) return; int mid=((l+r)>>1);
    		mdf(x<<1,l,mid,L,R,dt,kd),mdf(x<<1|1,mid+1,r,L,R,dt,kd);
    	}
    	void qry(int x,int l,int r,int ps,int len){
    		ps=min(ps,tg[x][0]),len=min(len,tg[x][1]);
    		if(l==r){write(min(ps-l+1,len));return;} int mid=((l+r)>>1);
    		qry(x<<1,l,mid,ps,len),qry(x<<1|1,mid+1,r,ps,len);
    	}
    }
    namespace SAM{
    	int len[M],rs[M],fa[M],t[M][26],F[M],C[M],T[M];
    	int now,cnt,ed,vs[M],sz[M],ps[M];
    	void init(){cnt=ed=1,now=0,memset(rs,-1,sizeof(rs));}
    	void ins(int c){
    		int x=ed; len[ed=++cnt]=++now,rs[ed]=now,sz[ed]=1;
    		while(x&&!t[x][c]) t[x][c]=ed,x=fa[x];
    		if(!x){fa[ed]=1;return;} int y=t[x][c];
    		if(len[y]==len[x]+1){fa[ed]=y;return;}
    		len[++cnt]=len[x]+1,fa[cnt]=fa[y],fa[y]=fa[ed]=cnt;
    		memcpy(t[cnt],t[y],sizeof(t[y]));
    		while(x&&t[x][c]==y) t[x][c]=cnt,x=fa[x];
    	}
    	void build(){
    		for(int i=1;i<=cnt;i++) C[len[i]]++;
    		for(int i=1;i<=n;i++) C[i]+=C[i-1];
    		for(int i=1;i<=cnt;i++) T[C[len[i]]--]=i;
    		for(int i=cnt;i>0;i--){
    			int x=T[i]; sz[fa[x]]+=sz[x];
    			if(sz[x]) rs[fa[x]]=rs[x]; if(sz[x]>1||!sz[x]) continue;
    			segtree::mdf(1,1,n,rs[x]-len[fa[x]],rs[x],len[fa[x]]+1,1);
    			segtree::mdf(1,1,n,rs[x]-len[x]+1,rs[x]-len[fa[x]]-1,rs[x],0);
    		}
    	}
    }
    int main(){
    	scanf("%s",S+1),n=strlen(S+1),SAM::init();
    	for(int i=1;i<=n;i++) SAM::ins(S[i]-'a');
    	segtree::init(),SAM::build();
    	segtree::qry(1,1,n,M,M),flush();return 0;
    }
  • 相关阅读:
    OpenCV特征描述
    OpenCV特征点检测
    expect实现无交互操作
    文件的修改时间
    sshd登录攻击
    tcp三次握手和syn 洪水攻击
    vim使用
    PHP拓展开发
    【转】LINUX 手动建立SWAP文件及删除
    Ubuntu下crontab命令的用法
  • 原文地址:https://www.cnblogs.com/OYJason/p/9811499.html
Copyright © 2011-2022 走看看