【ZJOI2015】诸神眷顾的幻想乡(广义后缀自动机)

来源:互联网 发布:淘宝卖家怎么删除订单 编辑:程序博客网 时间:2024/05/16 05:44

题目大意:

有一棵有n个节点的树,每个节点上有一个数字。
求所有树的路径中,所形成的字符串中不同的有多少个。
1<=n<=10^5
叶子节点数小于20。

题解:

其实我很不解一个裸的不能再裸的题为什么会是ZJOI Day1 的最后一题(暴%Po姐)。

也许是因为后缀自动机2012年才提出来吧。

首先注意叶子节点数小于20。

这启发我们以它们为根,去建树,这样会有20个trie,再合并,就有一棵大tried。

现在的问题在于求这棵trie的不同子串数(注意子串是自上到下的路径)。

这就是广义后缀自动机的裸题。

那么广义后缀自动机和后缀自动机有什么区别呢?

其实在我的眼里,并没有。

后缀自动机是一个串一直做到底。

对于广义后缀自动机(trie的后缀自动机),我只需要记录下trie上每个点加入它们以后的last,这样每个点加入的时候,从它父亲的记录下来的last开始搞就好了。

方案数就是step[x]step[pre[x]]

这个是后缀自动机的性质,广义当然同样适用。

答案没开long long导致1A失败。

Code:

#include<cstdio> #include<cstring>#define ll long long#define fo(i, x, y) for(int i = x; i <= y; i ++)using namespace std;const int N = 200005;int n, C, c[N], x, y, z, r[N], bz[N];struct edge {    int fi[N], nt[N], to[N], t;    void link(int x, int y) {        nt[++ t] = fi[x], to[t] = y, fi[x] = t;        nt[++ t] = fi[y], to[t] = x, fi[y] = t;    }} e;struct Trie {    int son[N * 20][10], t, last[N * 20];    int is(int x, int c) {        if(!son[x][c]) son[x][c] = ++ t;        return son[x][c];    }} a;struct suffix_automation {    ll ans;    int tot, lat, son[N * 20][10], pre[N * 20], step[N * 20];    #define push(u) step[++ tot] = u;    void extend(int last, int c) {        push(step[last] + 1);        int p = last, np = tot;        for(; p && !son[p][c]; p = pre[p]) son[p][c] = np;        if(!p) pre[np] = 1; else {            int q = son[p][c];            if(step[p] + 1 < step[q]) {                push(step[p] + 1);                int nq = tot;                memcpy(son[nq],son[q],sizeof son[q]);                pre[nq] = pre[q]; pre[q] = pre[np] = nq;                for(; son[p][c] == q; p = pre[p]) son[p][c] = nq;            } else pre[np] = q;        }        last = np;        ans += step[last] - step[pre[last]];        lat = last;    }} suf;void dg(int x) {    bz[x] = 1;    int zz = z;    for(int i = e.fi[x]; i; i = e.nt[i]) {        int y = e.to[i]; if(bz[y]) continue;        z = zz;        z = a.is(z, c[y]);        dg(y);    }    bz[x] = 0;}void dfs(int x, int y, int pc) {    if(x == 0) {        a.last[x] = suf.tot = suf.lat = 1;    } else {        suf.extend(a.last[y], pc);        a.last[x] = suf.lat;    }    fo(i, 0, C - 1) if(a.son[x][i]) {        int y = a.son[x][i];        dfs(y, x, i);    }}int main() {    scanf("%d %d", &n, &C);    fo(i, 1, n) scanf("%d", &c[i]);    fo(i, 1, n - 1) {        scanf("%d %d", &x, &y);        e.link(x, y); r[x] ++; r[y] ++;    }    fo(i, 1, n) if(r[i] == 1) {        z = a.is(0, c[i]);        dg(i);    }    dfs(0, 0, 0);    printf("%lld", suf.ans);}
阅读全文
1 0
原创粉丝点击