bzoj3879:SVT(接尾辞配列スタック単調+)

ポータル
のアイデア:接尾辞配列がメンテナンス脳+モノトーンスタックせずに使用することができ、もちろん、選択され S A メートル サム +仮想ツリー。
コード:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const ll mod=23333333333333333,N=1e6+5;
inline int read(){
    #define gc getchar
    int ans=0;
    char ch=gc();
    while(!isdigit(ch))ch=gc();
    while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
    return ans;
    #undef gc
}
char s[N];
namespace SA{
    int ht[N],rk[N],sa[N],sa2[N],st[N][20],Lg[N],pos[N],a[N],q[N],top,L[N],R[N],n,m;
    inline void Sort(){
        static int cnt[N];
        for(ri i=1;i<=m;++i)cnt[i]=0;
        for(ri i=1;i<=n;++i)++cnt[rk[i]];
        for(ri i=2;i<=m;++i)cnt[i]+=cnt[i-1];
        for(ri i=n;i;--i)sa[cnt[rk[sa2[i]]]--]=sa2[i];
    }
    inline void getsa(){
        n=strlen(s+1);
        for(ri i=1;i<=n;++i)rk[i]=s[i]-'a'+1,sa2[i]=i;
        m=127,Sort();
        for(ri w=1,p=0;m^n;p=0,w<<=1){
            for(ri i=n-w+1;i<=n;++i)sa2[++p]=i;
            for(ri i=1;i<=n;++i)if(sa[i]>w)sa2[++p]=sa[i]-w;
            Sort(),swap(sa2,rk);
            rk[sa[1]]=p=1;
            for(ri i=2;i<=n;++i)rk[sa[i]]=(sa2[sa[i]]==sa2[sa[i-1]]&&sa2[sa[i]+w]==sa2[sa[i-1]+w])?p:++p;
            m=p;
        }
        for(ri i=1,k=0,j;i<=n;ht[rk[i++]]=k)for(k?--k:k,j=sa[rk[i]-1];s[i+k]==s[j+k];++k);
        for(ri i=2;i<=n;++i)Lg[i]=Lg[i>>1]+1;
        for(ri i=1;i<=n;++i)st[i][0]=ht[i];
        for(ri j=1;j<20;++j)for(ri i=1;i<=n;++i)st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    }
    inline int query(int l,int r){
        int k=Lg[r-l+1];
        return min(st[l][k],st[r-(1<<k)+1][k]);
    }
    inline ll solve(){
        m=read();
        for(ri i=1;i<=m;++i)pos[i]=rk[read()];
        sort(pos+1,pos+m+1),m=unique(pos+1,pos+m+1)-pos-1;
        if(m<2)return 0;
        for(ri i=1;i<m;++i)a[i]=query(pos[i]+1,pos[i+1]);
        --m;
        top=0;
        for(ri i=1;i<=m;++i){
            while(top&&a[q[top]]>a[i])R[q[top--]]=i-1;
            q[++top]=i;
        }
        while(top)R[q[top--]]=m;
        for(ri i=m;i;--i){
            while(top&&a[q[top]]>=a[i])L[q[top--]]=i+1;
            q[++top]=i;
        }
        while(top)L[q[top--]]=1;
        ll ans=0;
        for(ri i=1;i<=m;++i)(ans+=(ll)(R[i]-i+1)*(i-L[i]+1)*a[i]%mod)%=mod;
        return ans;
    }
}
int m;
int main(){
    SA::n=read(),m=read();
    scanf("%s",s+1);
    SA::getsa();
    while(m--)cout<<SA::solve()<<'\n';
    return 0;
}

おすすめ

転載: blog.csdn.net/dreaming__ldx/article/details/93753831