*题目描述:
幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日。
粉丝们非常热情,自发组织表演了一系列节目给幽香看。幽香当然也非常高兴啦。
这时幽香发现了一件非常有趣的事情,太阳花田有n块空地。在过去,幽香为了方便,在这n块空地之间修建了n-1条边将它们连通起来。也就是说,这n块空地形成了一个树的结构。
有n个粉丝们来到了太阳花田上。为了表达对幽香生日的祝贺,他们选择了c中颜色的衣服,每种颜色恰好可以用一个0到c-1之间的整数来表示。并且每个人都站在一个空地上,每个空地上也只有一个人。这样整个太阳花田就花花绿绿了。幽香看到了,感觉也非常开心。
粉丝们策划的一个节目是这样的,选中两个粉丝A和B(A和B可以相同),然后A所在的空地到B所在的空地的路径上的粉丝依次跳起来(包括端点),幽香就能看到一个长度为A到B之间路径上的所有粉丝的数目(包括A和B)的颜色序列。一开始大家打算让人一两个粉丝(注意:A,B和B,A是不同的,他们形成的序列刚好相反,比如红绿蓝和蓝绿红)都来一次,但是有人指出这样可能会出现一些一模一样的颜色序列,会导致审美疲劳。
于是他们想要问题,在这个树上,一共有多少可能的不同的颜色序列(子串)幽香可以看到呢?
太阳花田的结构比较特殊,只与一个空地相邻的空地数量不超过20个。
*输入:
第一行两个正整数n,c。表示空地数量和颜色数量。
第二行有n个0到c-1之间,由空格隔开的整数,依次表示第i块空地上的粉丝的衣服颜色。(这里我们按照节点标号从小到大的顺序依次给出每块空地上粉丝的衣服颜色)。
接下来n-1行,每行两个正整数u,v,表示有一条连接空地u和空地v的边。
*输出:
一行,输出一个整数,表示答案。
*样例输入:
7 3
0 2 1 2 1 0 0
1 2
3 4
3 5
4 6
5 7
2 5
*样例输出:
30
*提示:
对于所有数据,1<=n<=100000, 1<=c<=10。
对于15%的数据,n<=2000。
另有5%的数据,所有空地都至多与两个空地相邻。
另有5%的数据,除一块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻。
另有5%的数据,除某两块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻
*题解:
广义后缀树(实际上是后缀自动机)。由于叶子节点不会很多,所以我们从每个叶子节点开始dfs,将路径上的字符串插入后缀自动机。这样每个两点间的路径串必然是后缀自动机的某个子串。于是乎问题就转化为了求广义后缀自动机上的不同子串的个数。
*代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> #ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif #ifdef CT
#define debug(...) printf(__VA_ARGS__)
#define setfile()
#else
#define debug(...)
#define filename ""
#define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif #define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
R char ch; R int cnt = 0; R bool minus = 0;
while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
ch == '-' ? minus = 1 : cnt = ch - '0';
while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
return minus ? -cnt : cnt;
}
#define maxn 200010
#define maxm 4000010
struct sam
{
sam *fa, *next[10];
int val;
}mem[maxm], *tot = mem, *pos[maxn];
inline sam *extend(R sam *p, R int c)
{
//if (p -> next[c] && p -> next[c] -> val == p -> val + 1)
// return p -> next[c];
if(p->next[c])
{
R sam *q = p->next[c];
if (q -> val == p -> val + 1)
return q;
else
{
R sam *nq = ++tot;
memcpy(nq -> next, q -> next, sizeof nq -> next);
nq -> val = p -> val + 1;
nq -> fa = q -> fa;
q -> fa = nq;
for ( ; p && p -> next[c] == q; p = p -> fa)
p -> next[c] = nq;
return nq;
}
}
R sam *np = ++tot;
np -> val = p -> val + 1;
for ( ; p && !p -> next[c]; p = p -> fa) p -> next[c] = np;
if (!p)
np -> fa = mem;
else
{
R sam *q = p -> next[c];
if (q -> val == p -> val + 1)
np -> fa = q;
else
{
R sam *nq = ++tot;
memcpy(nq -> next, q -> next, sizeof nq -> next);
nq -> val = p -> val + 1;
nq -> fa = q -> fa;
q -> fa = np -> fa = nq;
for ( ; p && p -> next[c] == q; p = p -> fa)
p -> next[c] = nq;
}
}
return np;
}
struct Edge
{
Edge *next;
int to;
}*last[maxn], e[maxm], *ecnt = e;
int deg[maxn], col[maxn];
inline void link(R int a, R int b)
{
++deg[a]; ++deg[b];
*++ecnt = (Edge) {last[a], b}; last[a] = ecnt;
*++ecnt = (Edge) {last[b], a}; last[b] = ecnt;
}
void dfs(R int x, R int fa)
{
pos[x] = extend(pos[fa], col[x]);
for (R Edge *iter = last[x]; iter; iter = iter -> next)
if (iter -> to != fa)
dfs(iter -> to, x);
}
int main()
{
// setfile();
R int n = FastIn(), c = FastIn();
for (R int i = 1; i <= n; ++i)
col[i] = FastIn();
for (R int i = 1; i < n; ++i)
link(FastIn(), FastIn());
pos[0] = mem;
for (R int i = 1; i <= n; ++i)
if (deg[i] == 1)
dfs(i, 0);
R long long ans = 0;
for (R sam *iter = mem + 1; iter <= tot; ++iter)
ans += iter -> val - iter -> fa -> val;
printf("%lld\n", ans );
return 0;
}
/*
7 3
0 2 1 2 1 0 0
1 2
3 4
3 5
4 6
5 7
2 5
*/

【bzoj3926】[Zjoi2015]诸神眷顾的幻想乡的更多相关文章

  1. bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 对[广义后缀自动机]的一些理解

    先说一下对后缀自动机的理解,主要是对构造过程的理解. 构造中,我们已经得到了前L个字符的后缀自动机,现在我们要得到L+1个字符的后缀自动机,什么需要改变呢? 首先,子串$[0,L+1)$对应的状态不存 ...

  2. BZOJ3926 [Zjoi2015]诸神眷顾的幻想乡 字符串 SAM

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ3926.html 题目传送门 - BZOJ3926 题意 给定一个有 $n$ 个节点,最多只有 $20$ ...

  3. BZOJ3926:[ZJOI2015]诸神眷顾的幻想乡(广义SAM)

    Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...

  4. [BZOJ3926][ZJOI2015]诸神眷顾的幻想乡(后缀自动机)

    日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦.  这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去 ...

  5. BZOJ3926 Zjoi2015 诸神眷顾的幻想乡【广义后缀自动机】

    Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...

  6. BZOJ3926 [Zjoi2015]诸神眷顾的幻想乡 【广义后缀自动机】

    题目 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴 ...

  7. BZOJ3926: [Zjoi2015]诸神眷顾的幻想乡(广义后缀自动机)

    Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...

  8. BZOJ3926 ZJOI2015诸神眷顾的幻想乡(广义后缀自动机)

    对多串建立SAM的一种方法是建trie再对trie建SAM.构造方式分为在线(也即不建trie而是依次插入每个串,或在trie上dfs)和离线(也即建好trie再bfs).其中离线构造与单串的构造方式 ...

  9. bzoj3926: [Zjoi2015]诸神眷顾的幻想乡

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  10. BZOJ3926 ZJOI2015 诸神眷顾的幻想乡 Trie、广义SAM

    传送门 树上的任意一条路径一定会在以某一个叶子节点为根的树上成为一条直上直下的链,而总共只有\(20\)个叶子节点. 于是每一次选所有叶子节点中的一个作为根,形成一个\(Trie\),把\(20\)个 ...

随机推荐

  1. LeetCode算法题-Flipping an Image(Java实现)

    这是悦乐书的第324次更新,第347篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第194题(顺位题号是832).给定二进制矩阵A,我们想要水平翻转图像,然后反转它,并返 ...

  2. 初学node.js-nodejs中实现用户注册路由

    经过前面几次的学习,已经可以做下小功能,今天要实现的事用户注册路由. 一.users_model.js  功能:定义用户对象模型 var mongoose=require('mongoose'), S ...

  3. 基于 @Scheduled 注解的 ----定时任务

    最常用的方法@Scheduled 注解表示起开定时任务 依赖 <dependencies> <dependency> <groupId>org.springfram ...

  4. ConfigurationManager.ConnectionStrings 属性

    public static ConnectionStringSettingsCollection ConnectionStrings { get; } App.config <?xml vers ...

  5. 前端 CSS 盒子模型 目录

    CSS盒子模型介绍 padding border属性

  6. UUID工具类及使用

    1.工具类: package UUIdtest; import java.util.UUID; public class UUIDUtil { public static String getUUID ...

  7. Linux文件拷贝(6)

    本篇介绍文件拷贝操作,主要讲两个命令: 命令 对应英文 作用 tree[目录名] tree 以树状图列出文件目录结构 cp 源文件 目标文件 copy 复制文件或者目录 tree tree命令可以将一 ...

  8. linux下安装phpunit

    安装pear 的命令如下: $ wget http://pear.php.net/go-pear.phar $ php go-pear.phar 如果报出PHP Warning:  file_exis ...

  9. 7.golang的字符串 string

    golang 字符串为不可变的量 ,字符串定义要使用双引号 package main import "fmt" func main() { var xx string = 'xxx ...

  10. Java中的四种权限修饰符

    权限修饰符   public protected [default] private 同一个类 YES YES YES YES 同一个包 YES YES YES NO 不同包子类 YES YES NO ...