zoukankan      html  css  js  c++  java
  • 【BZOJ #4556】【Tjoi2016&Heoi2016】—字符串(后缀自动机+线段树合并)

    传送门

    仍然和后缀数组做法一样考虑二分
    由于是公共前缀
    对反串建SamSam

    然后倍增找到C,C+midC,C+mid对应的那个节点
    就相当于看endposendpos是否有在a,bmid+1a,b-mid+1
    线段树合并维护$endpos即可

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=1<<20|1;
    inline char gc(){
        static char ibuf[RLEN],*ib,*ob;
        (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
        return (ob==ib)?EOF:*ib++;
    }
    #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 re register
    #define pii pair<int,int>
    #define pic pair<int,char>
    #define fi first
    #define se second
    #define pb push_back
    #define cs const
    #define bg begin
    #define poly vector<int>
    #define chemx(a,b) ((a)<(b)?(a)=(b):0)
    #define chemn(a,b) ((a)>(b)?(a)=(b):0)
    cs int N=100005;
    int n,m;
    namespace Seg{
    	cs int M=N*50;
    	int lc[M],rc[M],siz[M],tot;
    	#define mid ((l+r)>>1)
    	inline void insert(int &u,int l,int r,int p){
    		u=++tot;siz[u]++;
    		if(l==r)return;
    		if(p<=mid)insert(lc[u],l,mid,p);
    		else insert(rc[u],mid+1,r,p);
    	}
    	inline void merge(int &u,int r1,int r2){
    		if(!r1||!r2){u=r1+r2;return;}
    		u=++tot,siz[u]=siz[r1]+siz[r2];
    		merge(lc[u],lc[r1],lc[r2]);
    		merge(rc[u],rc[r1],rc[r2]);
    	}
    	inline int query(int u,int l,int r,int st,int des){
    		if(!u)return 0;
    		if(st<=l&&r<=des)return siz[u];
    		int res=0;
    		if(st<=mid)res+=query(lc[u],l,mid,st,des);
    		if(mid<des)res+=query(rc[u],mid+1,r,st,des);
    		return res;
    	}
    	#undef mid
    }
    namespace Sam{
    	cs int M=N<<1;
    	int nxt[M][26],fa[M],len[M],pos[M],rt[M],tot,last,ed[M];
    	inline void init(){
    		tot=last=1;
    	}
    	inline void insert(int c,int id){
    		int cur=++tot,p=last;
    		pos[cur]=id,ed[id]=cur;
    		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[p]==len[q]-1)fa[cur]=q;
    			else{
    				int clo=++tot;
    				len[clo]=len[p]+1,fa[clo]=fa[q];
    				memcpy(nxt[clo],nxt[q],sizeof(nxt[q]));
    				for(;p&&nxt[p][c]==q;p=fa[p])nxt[p][c]=clo;
    				fa[cur]=fa[q]=clo;
    			}
    		}
    	}
    	int buc[M],rk[M];
    	vector<int> e[M];
    	int f[M][20];
    	void dfs(int u){
    		for(int i=1;i<=18;i++)f[u][i]=f[f[u][i-1]][i-1];
    		for(int &v:e[u]){
    			f[v][0]=u,dfs(v);
    		}
    	}
    	inline void build(){
    		for(int i=1;i<=tot;i++)buc[len[i]]++;
    		for(int i=1;i<=tot;i++)buc[i]+=buc[i-1];
    		for(int i=1;i<=tot;i++)rk[buc[len[i]]--]=i;
    		for(int i=tot;i>=1;i--){
    			int u=rk[i];
    			if(pos[u])Seg::insert(rt[u],1,n,pos[u]);
    			Seg::merge(rt[fa[u]],rt[fa[u]],rt[u]);
    		}
    		for(int i=2;i<=tot;i++)e[fa[i]].pb(i);
    		dfs(1);
    	}
    	inline bool check(int l,int a,int b,int c,int d){
    		int u=ed[c];
    		for(int i=18;~i;i--)if(len[f[u][i]]>=l)u=f[u][i];
    		return Seg::query(rt[u],1,n,a,b-l+1)>0;
    	}
    	inline int query(int a,int b,int c,int d){
    		int l=1,r=min(d-c+1,b-a+1),res=0;
    		while(l<=r){
    			int mid=(l+r)>>1;
    			if(check(mid,a,b,c,d))l=mid+1,res=mid;
    			else r=mid-1;
    		}
    		return res;
    	}
    }
    char s[N];
    int main(){
    	n=read(),m=read();
    	Sam::init();
    	scanf("%s",s+1);
    	for(int i=n;i;i--)Sam::insert(s[i]-'a',i);
    	Sam::build();
    	for(int i=1;i<=m;i++){
    		int a=read(),b=read(),c=read(),d=read();
    		cout<<Sam::query(a,b,c,d)<<'
    ';
    	}
    }
    
    
    
  • 相关阅读:
    「运维之美」技术周刊 ( 第 2 期 )
    Win10下MySQL(5.7和8两个版本)忘记root密码的解决办法
    SpringBoot使用自定义注解实现简单参数加密解密(注解+HandlerMethodArgumentResolver)
    Set的交集、差集踩坑记录
    RocketMQ控制台命令
    IDEA远程连接和上传文件到服务器
    记录一下JProfiler的使用
    点击验证码刷新的实现
    算法学习:我终于明白二分查找的时间复杂度为什么是O(logn)了
    Ubuntu:一个部署好的tomcat应用(war包)怎么用Nginx实现动静分离?
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328445.html
Copyright © 2011-2022 走看看