bzoj4556(sam)

二分答案,(具体可见http://blog.csdn.net/neither_nor/article/details/51669114),然后就是判定问题,sa和sam都可以做,用sam写了一下,先用sam建后缀树,然后用主席树维护right集合就好了,每次判断把对应节点倍增到深度为mid的点,然后看一下他的子树里有没有right在对应区间的点就好了。

(前几天用sa写了一下,bz能A,洛谷一直WA,有空重构吧。。。)

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=200010,maxm=4000010;
int a,b,c,d,t,pos[maxn],cnt=1,cur,fa[maxn],ch[maxn][26],dis[maxn],n,m,tot;
char s[maxn];
int add(int c,int p){
    cur=++cnt;dis[cur]=dis[p]+1;
    for(;p&&!ch[p][c];p=fa[p])ch[p][c]=cur;
    if(!p)fa[cur]=1;
    else{
        int q=ch[p][c];
        if(dis[q]==dis[p]+1)fa[cur]=q;
        else{
            int nt=++cnt;dis[nt]=dis[p]+1;
            memcpy(ch[nt],ch[q],sizeof(ch[0]));
            fa[nt]=fa[q];fa[q]=fa[cur]=nt;
            for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nt;
        }
    }
    return cur;
}
vector<int>tong[maxn];
int root[maxn],siz[maxn],tim,last[maxn*2],pre[maxn*2],other[maxn*2],f[maxn][25],dfn[maxn],from[maxn];
void insert(int x,int y){++t;pre[t]=last[x];last[x]=t;other[t]=y;}
void dfs(int x){
    siz[x]=1;dfn[x]=++tim;from[tim]=x;
    for(int i=last[x];i;i=pre[i]){
        int v=other[i];
        f[v][0]=x;dfs(v);
        siz[x]+=siz[v];
    }
}
int jump(int x,int y){
    for(int i=20;i>=0;--i){
        if(dis[f[x][i]]>=y)x=f[x][i];
    }
    return x;
}
struct node{
    int l,r,v;
}tr[maxm];
void build(int pos,int l,int r,int &x){
    ++tot;tr[tot]=tr[x];x=tot;++tr[x].v;
    if(l==r)return;
    int mid=l+r>>1;
    if(pos<=mid)build(pos,l,mid,tr[x].l);
    else build(pos,mid+1,r,tr[x].r);
}
int qs(int i,int j,int l,int r,int L,int R){
    if(r<L||l>R||r<l)return 0;
    if(l>=L&&r<=R)return tr[j].v-tr[i].v;
    int mid=l+r>>1;
    return qs(tr[i].l,tr[j].l,l,mid,L,R)+qs(tr[i].r,tr[j].r,mid+1,r,L,R);
}
int pd(int mid){
    int op=jump(pos[c],mid);
    return qs(root[dfn[op]-1],root[dfn[op]+siz[op]-1],1,n,a,b-mid+1);
}
int main(){
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    int tmp=1;
    cin>>n>>m;
    scanf("%s",s+1);
    for(int i=n;i>=1;--i){
        tmp=add(s[i]-'a',tmp);
        pos[i]=tmp;
        tong[pos[i]].push_back(i);
    }
    for(int i=2;i<=cnt;++i)insert(fa[i],i);dfs(1);
    for(int j=1;j<=20;++j)
      for(int i=1;i<=cnt;++i){
        f[i][j]=f[f[i][j-1]][j-1];
    }
    for(int i=1;i<=tim;++i){
        int siz=tong[from[i]].size();root[i]=root[i-1];
        for(int j=0;j<siz;++j){
            build(tong[from[i]][j],1,n,root[i]);
        }
    }
    for(int i=1;i<=m;++i){
        scanf("%d%d%d%d",&a,&b,&c,&d);
        int l=1,r=min(d-c+1,b-a+1),ans=0;
        while(l<=r){
            int mid=l+r>>1;
            if(pd(mid))ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d
",ans);
    }
    //fclose(stdin);
    //fclose(stdout);
    //system("pause");
    return 0;
}
/*
50 1
pnzogoobycwczqfrbylxuwkgmnzlekbcakviijcrjahthagkcn
20 47 8 50
*/
原文地址:https://www.cnblogs.com/dibaotianxing/p/8393792.html