Luogu P3346 [ZJOI2015]诸神眷顾的幻想乡 广义SAM 后缀自动机
题目链接 \(Click\) \(Here\)
真的是好题啊~不过在说做法之前先强调几个自己总是掉的坑点。
更新节点永远记不住往上跳\(p = fa[p]\)
新建节点永远记不住\(len[y] = len[p] + 1\)
总之就是各种各样的智障错误啦!
来说这个题目。这个题目厉害就厉害在,你要想到怎么用只有\(20\)个叶子节点这个信息。对于任意一条树上的路径,它一定对应于以某个叶节点为根的树中,一条根节点发出的链上的后缀。既然叶节点只有\(20\)个,我们要做的就是换\(20\)次根就好了。由于是要搞根节点发出链上的后缀,所以我们事实上可以把这颗树当做一个\(Trie\)来使用。这样的话,每次把整颗\(Trie\)插入\(SAM\)中(新学的骚操作\(XD\)),最终求出所有节点的\(len[i] - len[fa[i]]\),就是不同子串个数了。
记得判重。把整颗\(Trie\)插进去的操作真的是学到了。
#include <bits/stdc++.h>
using namespace std;
const int N = 4000010;
struct Suffix_Auto {
int fa[N], len[N], ch[N][10];
int rt, las, cnt;
void Init () {
rt = las = cnt = 1;
memset (ch, 0, sizeof (ch));
memset (fa, 0, sizeof (fa));
memset (len, 0, sizeof (len));
}
int extend (int p, int c) {
if (ch[p][c] != 0) {
//已有节点
int x = ch[p][c];
if (len[x] == len[p] + 1) {
las = x;
} else {
int y = ++cnt; las = y;
len[y] = len[p] + 1;
fa[y] = fa[x];
fa[x] = y; //注意顺序
memcpy (ch[y], ch[x], sizeof (ch[x]));
while (p != 0 && ch[p][c] == x) {
ch[p][c] = y;
p = fa[p];
}
}
} else {
//单纯的插入
int q = ++cnt; las = q;
len[q] = len[p] + 1;
while (p != 0 && ch[p][c] == 0) {
ch[p][c] = q;
p = fa[p]; // 不要忘了这句啊
}
if (p == 0) {
fa[q] = rt;
} else {
int x = ch[p][c];
if (len[x] == len[p] + 1) {
fa[q] = x;
} else {
int y = ++cnt;
fa[y] = fa[x];
fa[x] = fa[q] = y;
len[y] = len[p] + 1;
memcpy (ch[y], ch[x], sizeof (ch[x]));
while (p != 0 && ch[p][c] == x) {
ch[p][c] = y;
p = fa[p];
}
}
}
}
return las;
}
long long get_ans () {
long long ans = 0;
for (int i = 1; i <= cnt; ++i) {
ans += len[i] - len[fa[i]];
}
return ans;
}
}sam;
int n, m, u, v, cnt, d[N], col[N], head[N];
struct edge {
int nxt, to;
}e[N << 1];
void add_edge (int from, int to){
e[++cnt].nxt = head[from];
e[cnt].to = to;
head[from] = cnt;
}
void get_tree (int u, int fa, int p) {
p = sam.extend (p, col[u]); //在p后面接上节点col[u]
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != fa) {
get_tree (v, u, p);
}
}
}
void add_len (int u, int v) {
add_edge (u, v);
add_edge (v, u);
}
int main () {
cin >> n >> m;
sam.Init ();
for (int i = 1; i <= n; ++i) {
cin >> col[i];
}
for (int i = 1; i <= n - 1; ++i) {
cin >> u >> v;
add_len (u, v);
++d[u], ++d[v];
}
for (int i = 1; i <= n; ++i) {
if (d[i] == 1) {
get_tree (i, 0, sam.rt);
//以i为树根跑一遍
}
}
cout << sam.get_ans () << endl;
}
Luogu P3346 [ZJOI2015]诸神眷顾的幻想乡 广义SAM 后缀自动机的更多相关文章
- BZOJ3926:[ZJOI2015]诸神眷顾的幻想乡(广义SAM)
Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...
- 洛谷P3346 [ZJOI2015]诸神眷顾的幻想乡(广义后缀自动机)
题意 题目链接 Sol 广义SAM的板子题. 首先叶子节点不超过20,那么可以直接对每个叶子节点为根的子树插入到广义SAM中. 因为所有合法的答案一定是某个叶子节点为根的树上的一条链,因此这样可以统计 ...
- BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡 [广义后缀自动机 Trie]
3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1124 Solved: 660[Submit][S ...
- 【BZOJ3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机
[BZOJ3926][Zjoi2015]诸神眷顾的幻想乡 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝 ...
- P3346 [ZJOI2015]诸神眷顾的幻想乡
思路 注意到叶子节点(度数为1)只有20个,可以分别以这20个节点为根,把所有子串插入SAM中,统计最后的本质不同的子串个数 所以就是广义SAM了 然后注意要判断一下有无重复插入 代码 #includ ...
- [洛谷P3346][ZJOI2015]诸神眷顾的幻想乡
题目大意:给你一棵$n$个点的树,最多有$20$个叶子节点,问共有几个不同的子串 题解:广义$SAM$,对每个叶子节点深搜一次,每个节点的$lst$设为这个节点当时的父亲,这样就可以时建出来的$SAM ...
- bzoj 3926 [Zjoi2015]诸神眷顾的幻想乡(SAM)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3926 [题意] 给定一棵树,每个节点都有相应的颜色,且保证叶子数不超过20,问 ...
- BZOJ3926 [Zjoi2015]诸神眷顾的幻想乡 字符串 SAM
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ3926.html 题目传送门 - BZOJ3926 题意 给定一个有 $n$ 个节点,最多只有 $20$ ...
- BZOJ.3926.[ZJOI2015]诸神眷顾的幻想乡(广义后缀自动机)
题目链接 要对多个串同时建立SAM,有两种方法: 1.将所有串拼起来,中间用分隔符隔开,插入字符正常插入即可. 2.在这些串的Trie上建SAM.实际上并不需要建Trie,还是只需要正常插入(因为本来 ...
随机推荐
- Java使用RabbitMQ之订阅分发(Topic)
使用RabbitMQ进行消息发布和订阅,生产者将消息发送给转发器(exchange),转发器根据路由键匹配已绑定的消息队列并转发消息,主题模式支持路由键的通配. 生产者代码: package org. ...
- CS新建排版
1.拉菜单栏barmanage,去掉不要的头部和尾部 ,选择控件bar属性optionsbar 全部为false,防止菜单拖动. 2.拉一个panelcontrol属性dock 设置顶部,在拉一个p ...
- Vue数组更新及过滤排序
前面的话 Vue为了增加列表渲染的功能,增加了一组观察数组的方法,而且可以显示一个数组的过滤或排序的副本.本文将详细介绍Vue数组更新及过滤排序 变异方法 Vue 包含一组观察数组的变异方法,它们将会 ...
- endnote插入文献时出现{,#}这样的乱码
1)在每次插入文献后,再点击一下Bibliography里面的Update Citation and Bibliography即可: (2)较好的解决方法也较为简单,只需要再一次进入Word中的End ...
- A Simple Problem with Integers(线段树区间更新模板)
最基本的线段树的区间更新及查询和 用tag(lazy)数组来“延缓”更新,查询或添加操作必须进行pushdown操作,即把tag从p传到lp和rp并清楚tag[p],既然得往lp和rp递归,那么就可以 ...
- JAVA web 使用有盟推送总结
仔细阅读文档,下边的都是废话. 为了省事,iOS和Android 提供了所有了参数,需要那个了修改传参. //ios actionURL为自定义参数 $.ajax({ type : "POS ...
- JarvisOJ Basic veryeasyRSA
已知RSA公钥生成参数: p = 3487583947589437589237958723892346254777 q = 8767867843568934765983476584376578389 ...
- 洛谷p1091合唱队形题解
题目 合唱队形首先要满足的是从1这个位置到中间任意的位置为单增的,从中间任意的位置到最后是单减的,且长度最长.这样才能满足出列的同学最少. 如果要满足这个条件那么我们可以先预处理出每个点的从前找的最长 ...
- 「SCOI2014」方伯伯的 OJ 解题报告
「SCOI2014」方伯伯的 OJ 和列队有点像,平衡树点分裂维护即可 但是需要额外用个set之类的对编号查找点的位置 插入完了后记得splay,删除时注意特判好多东西 Code: #include ...
- CF1131E String Multiplication(???)
这题难度2200,应该值了. 题目链接:CF原网 题目大意:定义两个字符串 $s$ 和 $t$($s$ 的长度为 $m$)的乘积为 $t+s_1+t+s_2+\dots+t+s_m+t$.定义一个字符 ...