BZOJ 3238 [Ahoi2013]差异

来源:互联网 发布:韩国视频软件 编辑:程序博客网 时间:2024/03/29 08:00

后缀自动机+后缀树

有一种不难想到的后缀数组的做法,详见黄学长题解

然而我做这题的目的主要是熟悉一下后缀自动机和后缀树- -

一个有趣的性质:反串的后缀自动机的parent树就是正串的后缀树,其树上的边权长度=parent树上儿子的len-父亲的len

构出后缀树之后就是一个小DP啦。

#include<cstdio>#include<cstring> #define N 500010#define S 28using namespace std;namespace ziqian{    typedef long long ll;    char s[N];    ll ans = 0;    int last[N*2], ecnt, siz[N*2]; struct edge{int next, to;}e[N<<1];    void addedge(int a, int b){e[++ecnt] = (edge){last[a], b}; last[a] = ecnt;}    struct SAM    {        SAM *par, *ch[S];        int len;    }mem[N*2], *tot, *null, *tai, *root;    SAM *newSAM(int l)    {        SAM *r = ++tot;        *r = *null;         r->len = l;        return r;    }    void init_SAM()    {        tot = mem;        null = ++tot;        null -> par = null;        for(int i = 0; i < S; i++) null->ch[i] = null;        null->len = 0;        root = newSAM(0);         tai = root;    }    void extend(int v)    {        SAM *p = tai, *np = newSAM(p->len + 1); tai = np; siz[np - mem] = 1;         for(; p != null && p->ch[v] == null; p = p->par) p->ch[v] = np;        if(p == null) np -> par = root;        else        {            SAM *q = p->ch[v];            if(p->len + 1 == q->len) np->par = q;            else            {                SAM *nq = newSAM(p->len + 1);                *nq = *q;                nq -> len = p->len + 1;                q->par = np->par = nq;                for(; p != null && p->ch[v] == q; p = p->par) p->ch[v] = nq;             }        }    }    void dp(int x)    {        for(int i = last[x]; i; i = e[i].next)        {            int y = e[i].to;            dp(y);            ans -= 2ll * siz[x] * siz[y] * (mem+x)->len;            siz[x] += siz[y];        }    }    void main()    {        scanf("%s",s+1);        int n = strlen(s+1);        init_SAM();        for(int i = n; i; i--) extend(s[i] - 'a');        for(int i = 1; i <= n; i++) ans += (ll) i * (n-1);        for(SAM *cur = tot; cur != mem; cur--)            addedge(cur->par - mem, cur - mem);        dp(root - mem);        printf("%lld\n",ans);    }}int main(){    ziqian::main();} 
0 0