洛谷P6640/LOJ#3298[BJOI2020]封印

口胡一发。

把 $s,t$ 扔一起建后缀数组,扫描线一下得出 $s$ 的每一个后缀和 $t$ 的 LCP 长度(以第 $i$ 个字符开始的记为 $lcp_i$),然后答案就是 $\max\limits^r_{i=l}\min(lcp_i,r-i+1)$,显然离线一下,根据 $i+lcp_i$ 和 $r+1$ 的大小关系分类,拿线段树扫一下即可。

时间复杂度 $O((|s|+|t|+q)\log(|s|+|t|))$。

代码:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<utility>
#include<numeric>
#define For(i,A,B) for(i=(A);i<=(B);++i)
#define Ford(i,B,A) for(i=(B);i>=(A);--i)
#define fi first
#define se second
using namespace std;
typedef pair<int,int> pii;
const int N=200050;
const int BUF=1<<21;
char rB[BUF],*rS,*rT,wB[BUF+50],*wT=wB;
inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,BUF,stdin),rS==rT)?EOF:*rS++;}
inline void flush(){fwrite(wB,1,wT-wB,stdout);wT=wB;}
inline int rdi(){
    char c=gc();
    while(!isdigit(c))c=gc();
    int x=c&15;
    for(c=gc();isdigit(c);c=gc())x=x*10+(c&15);
    return x;
}
inline void rds(char*s){
    char c=gc();
    while(!islower(c))c=gc();
    *s++=c;
    while(islower(c=gc()))*s++=c;
    *s='\0';
}
short buf[15];
inline void wt(int x){
    short l=-1;
    if(wT-wB>BUF)flush();
    while(x>9){
        buf[++l]=x%10;
        x/=10;
    }
    *wT++=x|48;
    while(l>=0)*wT++=buf[l--]|48;
    *wT++='\n';
}
char s[N*2];
int sa[N*2],t1[N*4],t2[N*4],c[N*2],rnk[N*2],h[N*2],maxn[N*4],ps[N],l[N],r[N],tr[N],ans[N];
pii lcp[N];
inline bool cmppii(const pii&a,const pii&b){return a.fi+a.se<b.fi+b.se;}
inline bool cmpi(int x,int y){return r[x]<r[y];}
inline void chkmin(int&a,int b){if(b<a)a=b;}
inline void chkmax(int&a,int b){if(a<b)a=b;}
void build(int o,int L,int R){
    if(L==R)ps[L]=o;
    else{
        int M=L+R>>1;
        build(o*2,L,M);
        build(o*2|1,M+1,R);
    }
}
inline void ins(int x,int k){
    for(int o=ps[x];o;o>>=1)chkmax(maxn[o],k);
}
int query(int o,int L,int R,int x,int y){
    if(x<=L&&y>=R)return maxn[o];
    int M=L+R>>1,ans=~0x3f3f3f3f;
    if(x<=M)ans=query(o*2,L,M,x,y);
    if(y>M)chkmax(ans,query(o*2|1,M+1,R,x,y));
    return ans;
}
int main(){
    int n,m,q,p=3,i,j,k,*x=t1,*y=t2,res;
    rds(s+1);n=strlen(s+1);
    s[n+1]='c';
    rds(s+n+2);m=strlen(s+n+2);
    For(i,1,n+m+1)++c[x[i]=s[i]-'a'+1];
    partial_sum(c+1,c+p+1,c+1);
    Ford(i,n+m+1,1)sa[c[x[i]]--]=i;
    for(k=1;k<=n+m;k<<=1){
        j=0;
        Ford(i,n+m+1,n+m-k+2)y[++j]=i;
        For(i,1,n+m+1)if(sa[i]>k)y[++j]=sa[i]-k;
        memset(c,0,sizeof(c));
        For(i,1,n+m+1)++c[x[i]];
        partial_sum(c+1,c+p+1,c+1);
        Ford(i,n+m+1,1)sa[c[x[y[i]]]--]=y[i];
        swap(x,y);
        p=1;
        For(i,1,n+m+1)x[sa[i]]=y[sa[i]]==y[sa[i+1]]&&y[sa[i]+k]==y[sa[i+1]+k]?p:p++;
        if(p>n+m+1)break;
    }
    For(i,1,n+m+1)rnk[sa[i]]=i;
    j=0;
    For(i,1,n+m+1)if(rnk[i]<=n+m){
        if(j)--j;
        while(s[i+j]==s[sa[rnk[i]+1]+j])++j;
        h[rnk[i]]=j;
    }
    res=0;
    For(i,1,n+m+1)if(sa[i]>n+1)res=h[i];
    else{
        if(sa[i]<=n)lcp[sa[i]].se=res;
        chkmin(res,h[i]);
    }
    res=0;
    Ford(i,n+m+1,1)if(sa[i]>n+1)res=h[i-1];
    else{
        if(sa[i]<=n)chkmax(lcp[sa[i]].se,res);
        chkmin(res,h[i-1]);
    }
    For(i,1,n)lcp[i].fi=i;
    sort(lcp+1,lcp+n+1,cmppii);
    build(1,1,n);
    iota(tr+1,tr+(q=rdi())+1,1);
    For(i,1,q){l[i]=rdi();r[i]=rdi();}
    sort(tr+1,tr+q+1,cmpi);
    memset(maxn,~0x3f,sizeof(maxn));
    j=1;
    For(i,1,q){
        for(;j<=n&&lcp[j].fi+lcp[j].se<=r[tr[i]];++j)ins(lcp[j].fi,lcp[j].se);
        ans[tr[i]]=query(1,1,n,l[tr[i]],r[tr[i]]);
    }
    memset(maxn,~0x3f,sizeof(maxn));
    j=n;
    Ford(i,q,1){
        for(;j&&lcp[j].fi+lcp[j].se>=r[tr[i]]+1;--j)ins(lcp[j].fi,-lcp[j].fi);
        chkmax(ans[tr[i]],r[tr[i]]+1+query(1,1,n,l[tr[i]],r[tr[i]]));
    }
    For(i,1,q)wt(ans[i]);
    flush();
    return 0;
}
View Code

 

posted @ 2020-07-08 16:10  wangyuchen  阅读(142)  评论(0编辑  收藏  举报