BZOJ5137 Standing Out from the Herd 广义SAM

传送门


仍然是广义SAM,仍然喜欢先建Trie然后在Trie上BFS建SAM的离线算法(因为感觉在线算法太玄学了

将所有串扔到一个Trie树上然后建SAM,对于SAM的每一个点\(x\)维护\(belong_x\)表示属于哪个串(如果属于多个串就\(-1\)),在\(suffix\ link\)改变的时候修改。

在计算答案之前一定要记得先在\(suffix\ link\)上递推一遍更新\(belong_x\),因为在插入某个字符\(p\)的时候,我们的做法是不断在\(parent\)树上跳,到达某个\(u\)满足\(trans_{u,p} \neq null\)的时候就停止并且更新\(belong_{trans_{u,p}}\),但是对于\(trans_{u,p}\)\(parent\)树上的祖先没有被更新。例如

2
baa
bba

如果不递推一遍就会输出3 2,但正确答案显然是2 2,具体原因是在插入\("bba"\)\(a\)字符的时候会将\("ba"\)所在的状态设为\(-1\),但是它在\(parent\)树上的祖先即\("a"\)所在的状态没有设为\(-1\)

最后对于每一个不是\(-1\)的SAM上的点统计一下答案就好。

#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<queue>
//This code is written by Itst
using namespace std;

const int MAXN = 2e5 + 3;
int ch[MAXN][26] , dep[MAXN] , ind[MAXN] , col[MAXN];
int N , cnt = 1;
char s[MAXN];
namespace SAM{
    int Lst[MAXN] , Sst[MAXN] , fa[MAXN] , trans[MAXN][26];
    int cnt = 1 , col[MAXN];
    int insert(int p , int l , int x , int c){
        int t = ++cnt;
        Lst[t] = l;
        col[t] = c;
        while(p && !trans[p][x]){
            trans[p][x] = t;
            p = fa[p];
        }
        if(!p){
            fa[t] = Sst[t] = 1;
            return t;
        }
        int q = trans[p][x];
        Sst[t] = Lst[p] + 2;
        if(Lst[q] == Lst[p] + 1){
            fa[t] = q;
            col[q] = col[q] != c ? -1 : col[q];
            return t;
        }
        int k = ++cnt;
        memcpy(trans[k] , trans[q] , sizeof(trans[k]));
        Lst[k] = Lst[p] + 1; Sst[k] = Sst[q];
        Sst[q] = Lst[p] + 2;
        col[k] = col[q] != c ? -1 : col[q];
        fa[k] = fa[q]; fa[q] = fa[t] = k;
        while(trans[p][x] == q){
            trans[p][x] = k;
            p = fa[p];
        }
        return t;
    }

    long long sum[MAXN];
    int in[MAXN];
    void work(){
        queue < int > q;
        for(int i = 2 ; i <= cnt ; ++i)
            ++in[fa[i]];
        for(int i = 2 ; i <= cnt ; ++i)
            if(!in[i])
                q.push(i);
        while(!q.empty()){
            int t = q.front();
            q.pop();
            if(t == 1)
                continue;
            if(col[t] != col[fa[t]])
                col[fa[t]] = -1;
            if(!--in[fa[t]])
                q.push(fa[t]);
        }
        for(int i = 2 ; i <= cnt ; ++i)
            if(col[i] != -1)
                sum[col[i]] += Lst[i] - Sst[i] + 1;
        for(int i = 1 ; i <= N ; ++i)
            cout << sum[i] << '\n';
    }
}

void insert(int ind){
    int cur = 1 , L = strlen(s + 1);
    for(int i = 1 ; i <= L ; ++i){
        if(!ch[cur][s[i] - 'a']){
            ch[cur][s[i] - 'a'] = ++cnt;
            col[cnt] = ind;
        }
        else
            col[ch[cur][s[i] - 'a']] = -1;
        cur = ch[cur][s[i] - 'a'];
    }
}

void build(){
    queue < int > q;
    q.push(ind[1] = 1);
    while(!q.empty()){
        int x = q.front();
        q.pop();
        for(int i = 0 ; i < 26 ; ++i)
            if(ch[x][i]){
                ind[ch[x][i]] = SAM::insert(ind[x] , dep[ch[x][i]] = dep[x] + 1 , i , col[ch[x][i]]);
                q.push(ch[x][i]);
            }
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    freopen("out","w",stdout);
#endif
    scanf("%d" , &N);
    for(int i = 1 ; i <= N ; ++i){
        scanf("%s" , s + 1);
        insert(i);
    }
    build();
    SAM::work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Itst/p/10432955.html
今日推荐