bzoj 3926 [Zjoi2015]诸神眷顾的幻想乡

来源:互联网 发布:计算机四级有用吗 知乎 编辑:程序博客网 时间:2024/04/29 08:14

资瓷点此阅读QvQ

Descripiton

给定一棵树,每个节点有一个字符,求从一个节点出发沿最短路径走到另一个节点所构成的字符串一共有多少种
注意:叶子数20

Solution

这个题,发现叶子数很少就很好做了,以每个叶子为根节点建立SAM即可,这样原树上所有路径都在SAM出现过,统计即可。

Code

#include <bits/stdc++.h>using namespace std;const int N = 100005 * 2 * 20, M = 10;typedef long long LL;#define pb push_backstruct SAM {    int tot, last, step[N], g[N], par[N], son[N][M], cnt[N], Q[N], ch[N], f[N];    void init() {        tot = 0;        memset(par, 0, sizeof(par));        par[0] = -1;        memset(son, 0, sizeof(son));    }    int add(int last, int x) {        int p = last, np = ++tot;        step[np] = step[p] + 1, last = np, ++g[np];//right        ch[np] = x;        for (; !son[p][x] && ~p; p = par[p])    son[p][x] = np;        if (p == -1)    return np;        int q = son[p][x];        if (step[q] == step[p] + 1) par[np] = q;        else {            step[++tot] = step[p] + 1;            ch[tot] = x;            int nq = tot;            memcpy(son[nq], son[q], sizeof(son[q]));            par[nq] = par[q];            par[np] = par[q] = nq;            for (; son[p][x] == q && ~p; p = par[p])    son[p][x] = nq;        }        return np;    }    void topo() {        for (int i = 1; i <= tot; ++i)    ++cnt[step[i]];        for (int i = 1; i <= tot; ++i)    cnt[i] += cnt[i - 1];        for (int i = 1; i <= tot; ++i)    Q[cnt[step[i]]--] = i;            }    LL gao() {        LL ans = 0;        for (int i = 1; i <= tot; ++i)  ans += step[i] - step[par[i]];//i状态表示多少个字符串        return ans;    }}S;int a[100005], d[100005];vector<int> g[100005];void dfs(int u, int fa, int last) {    int t = S.add(last, a[u]);    for (int i = 0; i < g[u].size(); ++i) {        int v = g[u][i];        if (v == fa)    continue;        dfs(v, u, t);    }}int main() {    S.init();    int n, c;    scanf("%d%d", &n, &c);    for (int i = 1; i <= n; ++i)    scanf("%d", &a[i]);    for (int i = 1, u, v; i < n; ++i) {        scanf("%d%d", &u, &v);        g[u].pb(v), g[v].pb(u);        ++d[u], ++d[v];    }    for (int i = 1; i <= n; ++i)        if (d[i] == 1)  dfs(i, 0, 0);    printf("%lld\n", S.gao());    return 0;}
0 0
原创粉丝点击