BZOJ1396 Identify substring 【SAM + SegmentTree】

BZOJ1396 Identify substring

Given a string \ (s \) , for each position in the string, output the shortest length of the substring that passes through this position and appears only once in \ (s \)

The simple idea is that we need to find those substrings that only appear once, then traverse each string, take the area covered by the string and the length of the string as \ (min \) to
consider optimization, and build it according to the \ (s \) string \ (SAM \) , and then calculate the size of the \ (endpos \) set of each state , where the series of substrings represented by the state of size \ (1 \) must appear only once in the original string, for \ ( endpos \) a state of size \ (1 \) \ (u \) , the shortest length of the substring it represents is \ (len_ {link_u} +1 \) , and the longest length is \ (len_u \) , Assuming that the end position of the substring is \ (firstpos_u \) , then for the interval of \ ([firstpos_u-len_ {link_u} + 1, firstpos_u] \) , you need to take \ (min \ with \ (len_ {link_u} \) ) , And for the interval \ ([firstpos_u-len_u + 1, firstpos_u-len_ {link_u}] \) , each position on the interval \ (i \) should be equal to \ (firstpos_u-i + 1 \)Take \ (min \) , you can only consider the contribution of \ (firstpos_u \) when updating, and you can subtract \ (i-1 \) in the final calculation , so according to the above method, you need to build two line tree To maintain, where the interval \ (min \) can be solved by first sorting and then directly assigning values

//#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;
}

Guess you like

Origin www.cnblogs.com/kikokiko/p/12709977.html