[SDOI2016]生成魔咒

\(SAM\)真牛逼(
又好理解,又好敲,我爱了。(对比\(SA\)

这是一个新的问题:考虑构建完\(SAM\),本质不同的子串个数。
利用endpos集合树的性质,那么答案为\(\sum len_u - len_{link_u}\)

[SDOI2016]生成魔咒
#include<cstdio>
#include<map>
#define Rint register int
using namespace std;
typedef long long LL;
const int N = 200003;
int n, now;
LL ans;
namespace SAM {
    map<int, int> ch[N];
    int last = 1, cnt = 1, l[N], fa[N];
    inline void ins(int c){
        int p = last, np = ++ cnt; last = np; l[np] = l[p] + 1;
        for(;!ch[p][c];p = fa[p]) ch[p][c] = np;
        if(!p) fa[np] = 1;
        else {
            int q = ch[p][c];
            if(l[q] == l[p] + 1) fa[np] = q;
            else {
                int nq = ++ cnt;
                l[nq] = l[p] + 1; ch[nq] = ch[q];
                fa[nq] = fa[q]; fa[q] = fa[np] = nq;
                for(;ch[p][c] == q;p = fa[p]) ch[p][c] = nq;
            }
        }
        ans += l[np] - l[fa[np]];
    }
}
int main(){
    scanf("%d", &n);
    for(Rint i = 1;i <= n;i ++){
        scanf("%d", &now);
        SAM :: ins(now);
        printf("%lld\n", ans);
    }
}
posted @ 2021-06-10 21:43  fhq_treap  阅读(37)  评论(0编辑  收藏  举报