A了但是疑惑
查看原帖
A了但是疑惑
421451
ReqCxmChtChr楼主2025/1/25 00:18

按照我自己对静态的后缀树理解,写出如下代码:

#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define ll long long
#define ull unsigned ll
#define db double
#define ldb long db
#define mp make_pair
#define fi first
#define se second
#define pii pair<int,int>
#define pbI push_back
#define inf 2e9
#define mdI int mid=(l+r)>>1
#define lowbit(x) ((x)&(-(x)))
#define rep(a,b,c) for(int a=(b);a<=(c);a++)
#define vep(a,b,c) for(int a=(b);a>=(c);a--)
#define MAXN 500010
#define gint __int128
#define MOD 1000000007//998244353
int qread(){
	char o=getchar();int f=1,x=0;
	for(;!isdigit(o);o=getchar())if(o=='-')f*=-1;
	for(;isdigit(o);o=getchar())x=x*10+o-'0';
	return f*x;
}
void chmx(db &x,db y){if(y>x)x=y;}
void chmx(int &x,int y){if(y>x)x=y;}
void chmi(int &x,int y){if(y<x)x=y;}
ll qp(ll a,ll b,ll p=MOD){
    ll bs=a,rs=1;while(b){if(b&1)rs=rs*bs%p;bs=bs*bs%p;b>>=1;}return rs;
}
bool FLA;
namespace SA{
    int n,m,w,ork[MAXN<<1],id[MAXN],cnt[MAXN];
    int rk[MAXN<<1],sa[MAXN],he[MAXN];string s;
    int Fil(){
        memcpy(ork,rk,sizeof(rk));
        int p=0;rep(i,1,n){if(ork[sa[i]]==ork[sa[i-1]]&&ork[sa[i]+w]==ork[sa[i-1]+w]){rk[sa[i]]=p;}else{rk[sa[i]]=++p;}}
        return p;
    }
    void Sort(int O){
        memset(cnt,0,sizeof(cnt));memcpy(id,sa,sizeof(sa));
        rep(i,1,n)cnt[rk[id[i]+O]]++;
        rep(i,1,m)cnt[i]+=cnt[i-1];
        for(int i=n;i>=1;i--)sa[cnt[rk[id[i]+O]]--]=id[i];
    }
    int st[20][MAXN],wh[20][MAXN],Lg2[MAXN];
    int ch[MAXN<<2][31],L[MAXN<<2],R[MAXN<<2],Va[MAXN<<2],Cnt,sz[MAXN<<2];
    int ren(int &x){return x?x:(x=++Cnt);}
    pii que(int l,int r){
        if(l==r){return mp(st[0][l],l);}
        int k=Lg2[r-l+1];
        if(st[k][l]<=st[k][r-(1<<k)+1]){return mp(st[k][l],wh[k][l]);}
        else{return mp(st[k][r-(1<<k)+1],wh[k][r-(1<<k)+1]);}
    }
    void build(int x,int l,int r){
        L[x]=l,R[x]=r,sz[x]=r-l+1;
        if(l==r){Va[x]=n-sa[l]+1;return;}
        int Cm=0,l1=l,V0=inf;
        while(l1<r){
            pii a=que(l1,r-1);
            if(a.fi<=V0){V0=a.fi;}else{break;}
            Cm++;
            build(ren(ch[x][Cm]),l1,a.se);
            l1=a.se+1;
        }
        Va[x]=V0;
        if(l1<=r)build(ren(ch[x][++Cm]),l1,r);
        assert(Cm<=30);
    }
    ll ans=0;
    void dfs(int x){
        //cerr<<"Id:"<<x<<" "<<L[x]<<" "<<R[x]<<" "<<Va[x]<<endl;
        //rep(i,1,26){
            //if(!ch[x][i])break;
            //cerr<<"Son:"<<ch[x][i]<<" "<<L[ch[x][i]]<<" "<<R[ch[x][i]]<<" "<<Va[ch[x][i]]<<endl;
        //}
        rep(i,1,30){
            if(ch[x][i]==0)break;
            dfs(ch[x][i]);
            ans+=((ll)sz[ch[x][i]])*(n-sz[ch[x][i]])*abs(Va[x]-Va[ch[x][i]]);
        }
    }
    void solve(string t){
        memset(rk,0,sizeof(rk));memset(sa,0,sizeof(sa));memset(he,0,sizeof(he));
        n=t.size(),m=127,w=0;s=" "+t;
        rep(i,1,n)sa[i]=i,rk[i]=s[i];
        Sort(0);
        Fil();for(w=1;w<=n;w<<=1){Sort(w);Sort(0);m=Fil();}
        int le=0;
        rep(i,1,n){
            if(rk[i]==n)continue;
            if(le)le--;while(s[i+le]==s[sa[rk[i]+1]+le])le++;
            he[rk[i]]=le;
        }
        rep(i,1,n)st[0][i]=he[i],wh[0][i]=i;
        Lg2[1]=0;rep(i,2,n)Lg2[i]=Lg2[i>>1]+1;
        rep(i,1,19){
            rep(j,1,n-(1<<i)+1){
                if(st[i-1][j]<=st[i-1][j+(1<<i-1)]){st[i][j]=st[i-1][j],wh[i][j]=wh[i-1][j];}
                else{st[i][j]=st[i-1][j+(1<<i-1)],wh[i][j]=wh[i-1][j+(1<<i-1)];}
            }
        }
        Cnt=1;build(1,1,n);dfs(1);cout<<ans;
        //assert(Cnt<2*MAXN);
    }
}
string s;
bool FLB;
signed main(){
    cerr<<((&FLB)-(&FLA))/1024.0/1024<<endl;
    cin>>s;
    SA::solve(s);
}

大概的意思是,对于sa[l...r]这段区间,以height[l...r-1]的所有最小值把区间分割开来,递归进行。L,R表示区间端点,Va为lcp(sa[l..r])。

height在这段区间内在k取最小值va,当且仅当这些后缀有公共前缀长度为va,后缀sa[k]和sa[k+1]的第va+1的点不一样,这种不一样理应至多有26次,但是我开到30才正确,否则Wa On 7和13,这是为何?

2025/1/25 00:18
加载中...