BZOJ1396部分文字列を特定する【SAM + SegmentTree】

BZOJ1396部分文字列を識別

文字列 \(s \)が 与えられた場合、文字列の 各位置について、この位置通過し、 \(s \)に 1回だけ現れる部分文字列の最短の長さを 出力します

単純なアイデアは、一度だけ出現する部分文字列を見つけ、各文字列をトラバースし、文字列で覆われている領域と文字列の長さを\(最小\)として
最適化考慮し、最初\(s \)文字列に従って作成する必要があるということです。\(SAM \)、次に各状態の\(endpos \)セットのサイズを計算します。ここでサイズ\(1 \)の状態によって表される一連のサブストリングは、\( endposの\)サイズ\(1 \)状態の\(U \) で表される最短のサブストリングの長さ\(} + +1 link_u LEN_ {\) 最大長さ\(len_u \) 部分文字列の終了位置が\(firstpos_u \)であるとすると、\([firstpos_u-len_ {link_u} + 1、firstpos_u] \)間隔では\(min \ with \(len_ {link_u} \)とる必要があります、そして区間\([firstpos_u-len_u + 1、firstpos_u-len_ {link_u}] \)の場合、区間\(i \)の各位置は\(firstpos_u-i + 1 \)等しくなければなりません\(min \)を取る更新時\(firstpos_u \)の寄与のみを考慮することができ、最終的な計算\(i-1 \)を差し引くことができるため、上記の方法に従って、2行のツリーを構築する必要があります。維持するには、間隔\(最小\)を最初にソートしてから直接値を割り当てることで解決できます

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
char s[MAXN];
struct SegmentTree{
    int lazy[MAXN<<2],l[MAXN<<2],r[MAXN<<2];
    #define ls(rt) rt << 1
    #define rs(rt) rt << 1 | 1
    void pushdown(int rt){
        if(!lazy[rt]) return;
        lazy[ls(rt)] = lazy[rt]; lazy[rs(rt)] = lazy[rt];
        lazy[rt] = 0;
    }
    void build(int L, int R, int rt = 1){
        l[rt] = L; r[rt] = R;
        if(l[rt] + 1 == r[rt]){
            lazy[rt] = MAXN;
            return;
        }
        int mid = (L + R) >> 1;
        build(L,mid,ls(rt)); build(mid,R,rs(rt));
    }
    void update(int L, int R, int x, int rt = 1){
        if(l[rt]>=R or L>=r[rt]) return;
        if(L<=l[rt] and r[rt]<=R){
            lazy[rt] = x;
            return;
        }
        pushdown(rt);
        update(L,R,x,ls(rt)); update(L,R,x,rs(rt));
    }
    int query(int pos, int rt = 1){
        if(l[rt] + 1 == r[rt]) return lazy[rt];
        int mid = (l[rt] + r[rt]) >> 1;
        pushdown(rt);
        if(pos<mid) return query(pos,ls(rt));
        else return query(pos,rs(rt));
    }
}ST1,ST2;
struct SAM{
    int len[MAXN],link[MAXN],ch[MAXN][26],tot,last,cnt[MAXN],c[MAXN],sa[MAXN],firstpos[MAXN];
    SAM(){ link[0] = -1; }
    void extend(int c){
        int np = ++tot, p = last;
        firstpos[np] = len[np] = len[p] + 1; cnt[np] = 1;
        while(p!=-1 and !ch[p][c]){
            ch[p][c] = np;
            p = link[p];
        }
        if(p==-1) link[np] = 0;
        else{
            int q = ch[p][c];
            if(len[p]+1==len[q]) link[np] = q;
            else{
                int clone = ++tot;
                len[clone] = len[p] + 1;
                link[clone] = link[q];
                firstpos[clone] = firstpos[q];
                memcpy(ch[clone],ch[q],sizeof(ch[q]));
                link[np] = link[q] = clone;
                while(p!=-1 and ch[p][c]==q){
                    ch[p][c] = clone;
                    p = link[p];
                }
            }
        }
        last = np;
    }
    void Radix_sort(){
        for(int i = 0; i <= tot; i++) c[i] = 0;
        for(int i = 0; i <= tot; i++) c[len[i]]++;
        for(int i = 1; i <= tot; i++) c[i] += c[i-1];
        for(int i = tot; i >= 0; i--) sa[c[len[i]]--] = i;
    }
    void solve(char *s){
        int l = strlen(s);
        for(int i = 0; i < l; i++) extend(s[i]-'a');
        Radix_sort();
        for(int i = tot + 1; i > 1; i--) cnt[link[sa[i]]] += cnt[sa[i]];
        vector<pair<int,pair<int,int> > > vec;
        for(int i = 1; i <= tot; i++) if(cnt[i]==1) vec.emplace_back(make_pair(firstpos[i],make_pair(len[link[i]]+1,len[i])));
        ST1.build(1,l+1); ST2.build(1,l+1);
        sort(vec.begin(),vec.end(),[](const pair<int,pair<int,int>> &lhs, const pair<int,pair<int,int>> &rhs){
            return lhs.second.first > rhs.second.first;
        });
        for(int i = 0; i < (int)vec.size(); i++) ST1.update(vec[i].first-vec[i].second.first+1,vec[i].first+1,vec[i].second.first);
        sort(vec.begin(),vec.end(),[](const pair<int,pair<int,int>> &lhs, const pair<int,pair<int,int>> &rhs){
            return lhs.first > rhs.first;
        });
        for(int i = 0; i < (int)vec.size(); i++) ST2.update(vec[i].first-vec[i].second.second+1,vec[i].first-vec[i].second.first+1,vec[i].first);
        for(int i = 1; i <= l; i++) printf("%d\n",min(ST1.query(i),ST2.query(i)-i+1));
    }
}sam;
int main(){
    scanf("%s",s);
    sam.solve(s);
    return 0;
}

おすすめ

転載: www.cnblogs.com/kikokiko/p/12709977.html