[BZOJ]3926 诸神眷顾的幻想乡(ZJOI2015)
听说大佬们都会后缀自动机。
小C看完SAM,想找个裸题练习一下模板。听说这题还是陈老师出的?(羊毛出在羊身上)
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是不同的,他们形成的序列刚好相反,比如红绿蓝和蓝绿红)都来一次,但是有人指出这样可能会出现一些一模一样的颜色序列,会导致审美疲劳。
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。
Solution
如果没学过后缀自动机可能会想到点分治(口胡),但是学了之后这就是一道裸题。
这里先发一个SAM的教程:https://huntzhan.org/suffix-automaton-tutorial/,感觉完爆陈老师在WC上讲的好几条街。(个人观点,不喜勿喷)
我们先从一条链入手,问题转化成一个字符串有多少本质不同的子串,我们可以用后缀自动机轻松解决。
只要你理解后缀自动机的原理,我们就知道将后缀自动机上的每个点对应的字符串的个数全部加起来就是答案。
同样,后缀自动机也适用于多个串。
这道题还有顺序的因素,把字符串反过来再插入SAM即可。
以上解决了树为一条链的情况。
题目告诉我们这棵树的叶子节点最多只有20个,肯定就是O(20n)的做法啊。
我们知道后缀自动机的插入操作实际上是在一个state后面再插入一个字符,我们只要记录下树上每个节点在本次遍历中对应的SAM中的state,插入一个节点就是在它父亲的state上插入即可。每次从一个叶子节点开始遍历整棵树,遍历一次就是构建了一棵树的SAM。
新插入的后缀可能已经存在于SAM中,小C做了一些小优化让自己舒服了一些。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define MS 10
#define MN 100005
#define MM 4000005
using namespace std;
struct edge{int nex,to;}e[MN<<];
int mxl[MM],lnk[MM],son[MM][MS];
int sta[MN],col[MN],din;
int hr[MN],d[MN],pin;
int n,m;
ll ans; inline int read()
{
int n=,f=; char c=getchar();
while (c<'' || c>'') {if(c=='-')f=-; c=getchar();}
while (c>='' && c<='') {n=n*+c-''; c=getchar();}
return n*f;
}
inline void ins(int x,int y) {e[++pin]=(edge){hr[x],y}; hr[x]=pin;} int samins(int ncol,int lasta)
{
int x=++din,lt;
for (lt=lasta;lasta!=-&&!son[lasta][ncol];lasta=lnk[lasta]) son[lasta][ncol]=x;
if (lt==lasta) --din; else mxl[x]=mxl[lt]+;
if (lasta==-) {lnk[x]=; return x;}
if (mxl[lasta]+==mxl[son[lasta][ncol]])
if (lt==lasta) return son[lasta][ncol];
else {lnk[x]=son[lasta][ncol]; return x;}
int y=++din,z=son[lasta][ncol];
memcpy(son[y],son[z],sizeof(son[y]));
lnk[y]=lnk[z]; mxl[y]=mxl[lasta]+; lnk[z]=y;
for (;son[lasta][ncol]==z;lasta=lnk[lasta]) son[lasta][ncol]=y;
if (x!=y) lnk[x]=y;
return x;
} void dfs(int x,int fat)
{
sta[x]=samins(col[x],sta[fat]);
for (register int i=hr[x];i;i=e[i].nex)
{
if (e[i].to==fat) continue;
dfs(e[i].to,x);
}
} int main()
{
register int i,x,y;
n=read(); m=read(); lnk[]=-;
for (i=;i<=n;++i) col[i]=read();
for (i=;i<n;++i)
{
x=read(); y=read();
ins(x,y); ins(y,x);
++d[x]; ++d[y];
}
for (i=;i<=n;++i)
if (d[i]==) {memset(sta,,sizeof(sta)); dfs(i,);}
for (i=;i<=din;++i) ans+=(ll)mxl[i]-mxl[lnk[i]];
printf("%lld",ans);
}
Last Word
之前对着陈老师在WC上的讲稿使劲艹,发现根本理解不能。(神犇的画风实在可怕)
然后随便在知乎上搜了搜,就看到一篇不错的教程,内容非常详尽,对关键点的分析也很到位。
看来找到好的资源也是学习的关键啊。非常感谢这样的有心人。
后缀自动机理解之后写起来意外地容易,本次默写给自己评个70分吧。
当然陈老师的讲稿也不能完全否定,至少比网络上一些博客有用得多得多。(orz WJMZBMR)
[BZOJ]3926 诸神眷顾的幻想乡(ZJOI2015)的更多相关文章
- BZOJ 3926 诸神眷顾的幻想乡
BZOJ 3926 诸神眷顾的幻想乡 开始看错题看成了每个点度数不超过20 后来翻了翻题解原来看错题的不止我一个 既然叶子数量不超过20,考虑树上的任何一条路径,以任何点为根时,如果它不是一条从上到下 ...
- bzoj 3926: 诸神眷顾的幻想乡 广义后缀自动机
题目: Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给 ...
- 诸神眷顾的幻想乡(zjoi2015,bzoj3926)(广义后缀自动机)
幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. ...
- 【BZOJ 3926】 [Zjoi2015]诸神眷顾的幻想乡 (广义SAM)
3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 974 Solved: 573 Descriptio ...
- BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡
3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1017 Solved: 599[Submit][S ...
- 字符串(广义后缀自动机):BZOJ 3926 [Zjoi2015]诸神眷顾的幻想乡
3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 843 Solved: 510[Submit][St ...
- BZOJ 3926 && ZJOI 2015 诸神眷顾的幻想乡 (广义后缀自动机)
3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MB Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽 ...
- BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡 [广义后缀自动机 Trie]
3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1124 Solved: 660[Submit][S ...
- BZOJ 3926: [Zjoi20150]诸神眷顾的幻想乡
3926: [Zjoi20150]诸神眷顾的幻想乡 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 438 Solved: 273 Descripti ...
随机推荐
- NetFPGA-1G-CML从零开始环境配置
NetFPGA-1G-CML从零开始环境配置 前言 偶得一块NetFPGA-1G-CML,跟着github对NetFPGA-1G-CML的入门指南,一步步把配置环境终于搭建起来,下面重新复现一下此过程 ...
- js 选择图片生成base64数据
<!doctype html> <html> <head> <meta charset="utf-8"> <meta http ...
- NOIP2016 天天爱跑步 80分暴力
https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...
- [NOI2015]软件包管理器
4621 [NOI2015]软件包管理器 题目等级 : 钻石 Diamond 题目描述 Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过 ...
- css精简命名
想写写前言啥的,发现自己是前言无能星人. 简单吐吐槽好了,来到新公司,接手公司之前的项目,我想着也就是改改bug,慢慢来吧,粗略看了看这个项目的代码,目前仅看了html和css样式的,忍不住吐血三升. ...
- python 面向对象设计思想发展史
这篇主要说的是程序设计思想发展历史,分为概述和详细发展历史 一,概述 1940年以前:面向机器 最早的程序设计都是采用机器语言来编写的,直接使用二进制码来表示机器能够识别和执行的 指令和数 据.简单来 ...
- Spark学习笔记之RDD中的Transformation和Action函数
总算可以开始写第一篇技术博客了,就从学习Spark开始吧.之前阅读了很多关于Spark的文章,对Spark的工作机制及编程模型有了一定了解,下面把Spark中对RDD的常用操作函数做一下总结,以pys ...
- javascript中获取dom元素的高度和宽度
javascript中获取dom元素高度和宽度的方法如下: 网页可见区域宽: document.body.clientWidth网页可见区域高: document.body.clientHeight网 ...
- 【52ABP实战教程】00-- ASP.NET CORE系列介绍
为什么是.net core? 记得在半年前.NET CORE刚刚出了1.0,当时有朋友推荐我使用的时候,个人觉得还不成熟. 现在.NET Core已经到了2.0,.NET Standard 2.0 添 ...
- Linux:sheel脚本for的用法,及日期参数+1day用法
记录下shell的for的用法,及参数是日期的情况下,该日期+1day的用法: #!/usr/bin/env bash source /app/catt/login.sh p_days="2 ...