题意:给定一棵树,每个节点有一个颜色,问树上有多少种子串(定义子串为某两个点上的路径),保证叶子节点数<=20。n<=10^5

题解:

叶子节点小于等于20,考虑将每个叶子节点作为根把树给提起来形成一棵trie,然后定义这棵树的子串为从上到下的一个串(深度从浅到深)。

这样做我们可以发现每个子串必定是某棵trie上的一段直线。统计20棵树的不同子串只需要把它们建到一个自动机上就行了,相当于把20棵trie合并成一棵大的。
对于每个节点x,它贡献的子串数量是max[x]-min[x],又因为min[x]=max[fa]+1,则=max[x]-max[fa],就是step[x]-step[fa];
学会了怎样在sam上插入一颗trie,就直接记录一下父亲在sam上的节点作为p。注意每次都要新开一个点,不然会导致无意义的子串出现。

例如一棵树 (括号内为i颜色)

1(0)

2(1)

3(2)  4(3)

2是1的孩子,3和4都是2的孩子。在以1为根节点的时候插入了这棵trie,在以3为根节点的时候son[root][2]已经存在,如果用它来当现在的点的话就会让一棵trie接在另一棵的末位,导致无意义的子串出现,答案偏大。

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std; typedef long long LL;
const int N=*;
int n,c,tot,len,last;
int w[N],son[N][],step[N],pre[N],first[N],cnt[N],id[N];
struct node{
int x,y,next;
}a[*N]; void ins(int x,int y)
{
a[++len].x=x;a[len].y=y;
a[len].next=first[x];first[x]=len;
} int add_node(int x)
{
step[++tot]=x;
return tot;
} int extend(int p,int ch)
{
// int np;
// if(son[p][ch]) return son[p][ch];
// else np=add_node(step[p]+1);
int np=add_node(step[p]+);//debug 每次都要新开一个点 while(p && !son[p][ch]) son[p][ch]=np,p=pre[p];
if(p==) pre[np]=;
else
{
int q=son[p][ch];
if(step[q]==step[p]+) pre[np]=q;
else
{
int nq=add_node(step[p]+);
memcpy(son[nq],son[q],sizeof(son[q]));
pre[nq]=pre[q];
pre[np]=pre[q]=nq;
while(son[p][ch]==q) son[p][ch]=nq,p=pre[p];
}
}
last=np;
return np;
} void dfs(int x,int fa,int now)
{
int nt=extend(now,w[x]);
// printf("%d\n",nt);
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(y!=fa) dfs(y,x,nt);
}
} int main()
{
freopen("a.in","r",stdin);
scanf("%d%d",&n,&c);
for(int i=;i<=n;i++) scanf("%d",&w[i]);
tot=;len=;
memset(son,,sizeof(son));
memset(pre,,sizeof(pre));
memset(cnt,,sizeof(cnt));
memset(first,,sizeof(first));
step[++tot]=;last=;
for(int i=;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ins(x,y);ins(y,x);
cnt[x]++;cnt[y]++;
}
// for(int i=1;i<=len;i++) printf("%d -- > %d\n",a[i].x,a[i].y);
for(int i=;i<=n;i++)
{
if(cnt[i]==) dfs(i,,);
}
// for(int i=1;i<=tot;i++) printf("%d ",id[i]);printf("\n");
LL ans=;
for(int i=;i<=tot;i++) ans+=(LL)(step[i]-step[pre[i]]);
printf("%lld\n",ans);
return ;
}

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

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

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

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

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

  3. bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机模板

    #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #d ...

  4. Luogu P3346 [ZJOI2015]诸神眷顾的幻想乡 广义SAM 后缀自动机

    题目链接 \(Click\) \(Here\) 真的是好题啊-不过在说做法之前先强调几个自己总是掉的坑点. 更新节点永远记不住往上跳\(p = fa[p]\) 新建节点永远记不住\(len[y] = ...

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

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

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

    [BZOJ3926][Zjoi2015]诸神眷顾的幻想乡 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝 ...

  7. BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡 [广义后缀自动机 Trie]

    3926: [Zjoi2015]诸神眷顾的幻想乡 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1124  Solved: 660[Submit][S ...

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

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

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

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

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

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

随机推荐

  1. C语言RL78 serial bootloader和C#语言bootloader PC端串口通信程序

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 前段时间完成的hype ...

  2. 前端学习webpack

    ### 模块化- 为了保证代码充分解耦,一个大的项目拆分成互相依赖的一个一个的小的模块,最后再通过简单的方式合并在一起- 每一个js文件都可以看成一个单独的模块在node这边(服务器端),提出Comm ...

  3. 如何删除TFS项目

    TFS是先建集合,再在集合下面建项目.删除的时候,需要先删除项目,再删除集合,然后重新建.具体步骤如下: 1.删除项目        删除项目必须通过命令来进行删除,调用TFSDeleteProjec ...

  4. cocos2d-x 场景切换

    场景切换的方法 场景切换是通过导演类director实现的,其中的相关方法如下: director.run(new_scene).该方法可以运行场景,只能在启动第一个场景时调用该方法.如果已运行场景, ...

  5. pep8介绍

    pep8介绍: PEP8是针对python代码格式而编订的风格指南,采用一致的编码风格可以令代码更加易懂易读! (1)空白: python中空白会影响代码的含义及其代码的清晰程度 使用space(空格 ...

  6. 学习人工智能的第六个月[深度学习[Deep Learning,DL]]

    这个月阅读了论文[Partial Adversarial Domain Adaptation-eccv18],文章着眼于源域标签空间包含目标域标签空间的场景,在域对抗神经网络的基础上提出了部分对抗域适 ...

  7. java面向对象课程设计-数学表达式计算器

    项目简介 设计一个计算器,其能够: 1)由用户输入一个简单的四则运算表达式,求出其计算结果后显示. 2)特殊数学函数,如:绝对值.取整.三角函数.倒数.平方根.平方.立方等. 3)对一定范围内的数字将 ...

  8. vue.js的特点-1

    1. Vue.js是数据驱动的,无需手动操作DOM. 它通过一些特殊的HTML语法,将DOM和数据绑定起来.一旦你创建了绑定,DOM将和数据保持同步,每当变更了数据,DOM也会相应的更新. 2. MV ...

  9. Chromium学习笔记

    1. How to build chromium Follow the steps on:http://www.chromium.org/Home 需要安装Win7 x64的OS,PC的配置尽可能高端 ...

  10. CSS的基本使用

    CSS的出现就是为了将HTML的内容与样式分离 CSS的书写方式 selector{ key:value } h1{ color: blue; } <!DOCTYPE html> < ...