您的位置:首页 > 其它

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

2015-11-23 16:08 351 查看

资瓷点此阅读QvQ

Descripiton

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

注意:叶子数≤\le20

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_back
struct SAM {
int tot, last, step
, g
, par
, son
[M], cnt
, Q
, ch
, f
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: