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

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

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 1017  Solved: 599
[Submit][Status][Discuss]

Description

幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的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个。

Input

第一行两个正整数n,c。表示空地数量和颜色数量。

第二行有n个0到c-1之间,由空格隔开的整数,依次表示第i块空地上的粉丝的衣服颜色。(这里我们按照节点标号从小到大的顺序依次给出每块空地上粉丝的衣服颜色)。

接下来n-1行,每行两个正整数u,v,表示有一条连接空地u和空地v的边。

Output

一行,输出一个整数,表示答案。

Sample Input

7 3
0 2 1 2 1 0 0
1 2
3 4
3 5
4 6
5 7
2 5

Sample Output

30

HINT

对于所有数据,1<=n<=100000, 1<=c<=10。

对于15%的数据,n<=2000。

另有5%的数据,所有空地都至多与两个空地相邻。

另有5%的数据,除一块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻。

另有5%的数据,除某两块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻

Source

[Submit][Status][Discuss]

OTZ 陈老师高深莫测的语文技巧……

通过对本短片小说最后一行的仔细观察,不难看出这块奇葩的田地形成了一棵至多只有20个叶子节点的树(然而我看了半天都没发现)。

所以从这至多20个节点出发,向根DFS,建立广义自动机,那么树上的每一条路径都是一个可被SAM接受的子串,答案极为SAM中不同的子串个数,累加最长路差值即可。

  1 #include <bits/stdc++.h>
  2
  3 /* MYSCANNER */
  4
  5 #define siz 1024
  6
  7 inline int get_c(void)
  8 {
  9     static char buf[siz];
 10     static char *head = buf + siz;
 11     static char *tail = buf + siz;
 12
 13     if (head == tail)
 14         fread(head = buf, 1, siz, stdin);
 15
 16     return *head++;
 17 }
 18
 19 inline int get_i(void)
 20 {
 21     register int ret = 0;
 22     register int neg = false;
 23     register int bit = get_c();
 24
 25     for (; bit < 48; bit = get_c())
 26         if (bit == ‘-‘)neg ^= true;
 27
 28     for (; bit > 47; bit = get_c())
 29         ret = ret * 10 + bit - ‘0‘;
 30
 31     return neg ? -ret : ret;
 32 }
 33
 34 const int maxn = 2000100;
 35
 36 /* AUTOMATON */
 37
 38 int tail = 1;
 39 int root[maxn];
 40 int step[maxn];
 41 int fail[maxn];
 42 int next[maxn][15];
 43
 44 inline int extend(int p, int c)
 45 {
 46     if (next[p][c] && step[next[p][c]] == step[p] + 1)
 47         return next[p][c];
 48     int t = tail++;
 49     step[t] = step[p] + 1;
 50     while (p && !next[p][c])
 51         next[p][c] = t, p = fail[p];
 52     if (p)
 53     {
 54         int q = next[p][c];
 55         if (step[q] == step[p] + 1)
 56             fail[t] = q;
 57         else
 58         {
 59             int k = tail++;
 60             fail[k] = fail[q];
 61             fail[q] = fail[t] = k;
 62             step[k] = step[p] + 1;
 63             memcpy(next[k], next[q], sizeof(next[k]));
 64             while (p && next[p][c] == q)
 65                 next[p][c] = k, p = fail[p];
 66         }
 67     }
 68     else
 69         fail[t] = 1;
 70     return t;
 71 }
 72
 73 /* GRAPH */
 74
 75 int n;
 76 int m;
 77 int tot;
 78 int hd[maxn];
 79 int nt[maxn];
 80 int to[maxn];
 81 int cnt[maxn];
 82 int col[maxn];
 83 int vis[maxn];
 84 int que[maxn];
 85
 86 inline void addEdge(int x, int y)
 87 {
 88     nt[++tot] = hd[x]; to[tot] = y; hd[x] = tot;
 89     nt[++tot] = hd[y]; to[tot] = x; hd[y] = tot;
 90 }
 91
 92 void DFS(int u, int f)
 93 {
 94     root[u] = extend(root[f], col[u]);
 95     for (int i = hd[u]; i; i = nt[i])
 96         if (to[i] != f)DFS(to[i], u);
 97 }
 98
 99 /* MAIN FUNC */
100
101 signed main(void)
102 {
103     n = get_i();
104     m = get_i();
105
106     for (int i = 1; i <= n; ++i)
107         col[i] = get_i();
108
109     for (int i = 1; i < n; ++i)
110     {
111         int x = get_i();
112         int y = get_i();
113         addEdge(x, y);
114         ++cnt[x];
115         ++cnt[y];
116     }
117
118     root[0] = tail++;
119
120     for (int i = 1; i <= n; ++i)
121         if (cnt[i] == 1)DFS(i, 0);
122
123     long long ans = 0LL;
124
125     int head = 0, tail = 0;
126
127     que[tail++] = 1;
128
129     while (head != tail)
130     {
131         int t = que[head++];
132         if (t != 1)
133             ans += step[t] - step[fail[t]];
134         for (int i = 0; i < m; ++i)
135             if (next[t][i] && !vis[next[t][i]])
136                 vis[next[t][i]] = 1, que[tail++] = next[t][i];
137     }
138
139     printf("%lld\n", ans);
140 }

@Author: YouSiki

时间: 2024-10-13 04:56:43

BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡的相关文章

字符串(广义后缀自动机):BZOJ 3926 [Zjoi2015]诸神眷顾的幻想乡

3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 843  Solved: 510[Submit][Status][Discuss] Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n

BZOJ 3926 Zjoi2015 诸神眷顾的幻想乡 后缀自动机

题目大意:给定一棵树,每个节点有一个字符,求从一个节点出发沿最短路径走到另一个节点所构成的字符串一共有多少种 此生无悔入东方,来世愿生幻想乡 题目戳这里 注意一句话:太阳花田的结构比较特殊,只与一个空地相邻的空地的数量不超过20个 有奖问答:↑你看到这句话的第一反应是啥? 1.度数<=20 2.叶节点数<=20 仔细看几遍就能找到答案~ [捂脸熊]陈老师真是语文高手.... 叶节点数<=20还做啥了... 直接从每个叶节点DFS一遍,然后构建广义后缀自动机,最终答案就是每个节点的深度-p

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

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3926题解&&代码: 后缀自动机,Trie树 如果以每个叶子为根,所有的子串一定在某一颗树的一条由祖先到子孙的链上. 由于叶子节点只有不超过20个,那么就可以从每个叶子开始dfs,把每个从根开始的串都加入一颗trie树. 显然,所有的子串都在trie树上,那么现在就需要统计trie树上有多少不同的子串. 对trie树建立后缀自动机,然后统计不同的子串个数即可. (本人不会在线建立tri

BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机 后缀自动机 字符串

https://www.lydsy.com/JudgeOnline/problem.php?id=3926 广义后缀自动机是一种可以处理好多字符串的一种数据结构(不像后缀自动机只有处理一到两种的时候比较方便). 后缀自动机可以说是一种存子串的缩小点数的trie树,广义后缀自动机就是更改了一下塞点的方式让它可以塞多个子串. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<

BZOJ 3926: [Zjoi20150]诸神眷顾的幻想乡

3926: [Zjoi20150]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 438  Solved: 273 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去,幽香为了方便,在这n块空地之间修

bzoj 3926 [Zjoi20150]诸神眷顾的幻想乡(SAM)

3926: [Zjoi20150]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 615  Solved: 369[Submit][Status][Discuss] Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有

BZOJ 3926: [Zjoi20150]诸神眷顾的幻想乡(后缀自动机)

被这道题坑了= =只与一个空地相连的空地不超过20个只与一个空地相连的空地不超过20个 因为很重要所以说两遍 就是说儿子节点最多只有20个 把这20个节点作为根遍历一遍所得到的tire所得到的所有不同子串就是答案了 怎么求? 这可是CLJ出的啊 想想她讲过什么 后缀自动机或可持久化后缀数组的经典应用 由于不会打可持久化后缀数组,就打了个自动机 自己对后缀自动机根本不熟,找时间在多做几道题 CODE: #include<cstdio> #include<iostream> #incl

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

传送门 一个广义后缀自动机模板. //Achen #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<queue> #include<cmath> const int N=4000007; typedef long long LL

【BZOJ 3926】 [Zjoi2015]诸神眷顾的幻想乡 (广义SAM)

3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 974  Solved: 573 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去,幽香为了方便,在这n块空地之间修建