后缀自动机扩展到树形结构上。

先建出大的Trie,然后我们得到了一棵Trie树,对于树上的每个节点,保存一个后缀自动机从根走它代表的字符串后到达的节点,每次其儿子就从父亲的这个节点开始扩展。

 /**************************************************************
Problem: 3926
User: idy002
Language: C++
Result: Accepted
Time:4320 ms
Memory:460976 kb
****************************************************************/ #include <cstdio>
#include <cassert>
#include <cstring>
#include <algorithm>
#define N 100010
#define ST 3000100
#define SS ST<<1
using namespace std; typedef long long dnt; int qu[SS], stk[SS], bg, ed, top; struct Sam {
int son[SS][], val[SS], pnt[SS], ntot;
Sam() { pnt[] = -; };
int append( int p, int c ) {
int np = ++ntot;
val[np] = val[p]+;
while( p!=- && !son[p][c] )
son[p][c]=np, p=pnt[p];
if( p==- ) {
pnt[np] = ;
} else {
int q=son[p][c];
if( val[q]==val[p]+ ) {
pnt[np] = q;
} else {
int nq = ++ntot;
memcpy( son[nq], son[q], sizeof(son[nq]) );
val[nq] = val[p]+;
pnt[nq] = pnt[q];
pnt[q] = pnt[np] = nq;
while( p!=- && son[p][c]==q )
son[p][c]=nq, p=pnt[p];
}
}
return np;
}
dnt count() {
dnt rt = ;
for( int u=; u<=ntot; u++ )
rt += val[u]-val[pnt[u]];
return rt;
}
}sam;
struct Trie {
int son[ST][], last[ST], ntot;
void insert( int *T ) {
int u=;
for( int i=; T[i]!=-; i++ ) {
int c=T[i];
if( !(<=T[i]&&T[i]<) ) {
assert( T[i]>= && T[i]<= );
}
if( !son[u][c] ) son[u][c]=++ntot;
u=son[u][c];
}
}
void build() {
last[] = ;
qu[bg=ed=] = ;
while( bg<=ed ) {
int u=qu[bg++];
for( int c=; c<; c++ ) {
int v=son[u][c];
if( !v ) continue;
last[v] = sam.append( last[u], c );
qu[++ed] = v;
}
}
}
}trie; int n, c;
int head[N], wght[N], dest[N<<], next[N<<], etot;
int dgr[N], fat[N]; void adde( int u, int v ) {
etot++;
dest[etot] = v;
next[etot] = head[u];
head[u] = etot;
}
void bfs( int s ) {
qu[bg=ed=] = s;
fat[s] = ;
while( bg<=ed ) {
int u=qu[bg++];
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==fat[u] ) continue;
qu[++ed] = v;
fat[v] = u;
}
}
for( int t=; t<=top; t++ ) {
int u=stk[t];
bg=, ed=;
while( u ) {
qu[++ed] = wght[u];
u=fat[u];
}
reverse( qu+, qu++ed );
qu[++ed] = -;
trie.insert( qu+ );
}
}
int main() {
scanf( "%d%d", &n, &c );
for( int i=; i<=n; i++ )
scanf( "%d", wght+i );
for( int i=,u,v; i<n; i++ ) {
scanf( "%d%d", &u, &v );
adde( u, v );
adde( v, u );
dgr[u]++, dgr[v]++;
}
for( int u=; u<=n; u++ )
if( dgr[u]<= ) stk[++top] = u;
for( int t=; t<=top; t++ )
bfs(stk[t]);
trie.build();
printf( "%lld\n", sam.count() );
return ;
}

最新文章

  1. sharePoint 2016 弃用和删除的功能
  2. AC日记——字符串P型编码 openjudge 1.7 31
  3. A.Kaw矩阵代数初步学习笔记 8. Gauss-Seidel Method
  4. XAML语言介绍
  5. hdu----(1402)A * B Problem Plus(FFT模板)
  6. jqGrid中实现radiobutton的两种做法
  7. 预定义的类型“Microsoft.CSharp.RuntimeBinder.Binder”未定义或未导入
  8. 一种快速求fibonacci第n个数的算法
  9. 转载 VPN介绍
  10. springMVC 中几种获取request和response的方式
  11. Jquery的树插件jqxTreeGrid的使用小结
  12. 使用Boost program_options控制程序输入
  13. BeanUtils 读取数据
  14. 本地代码上传到git
  15. vue源码分析—模板解析
  16. Vue获取dom和数据监听
  17. Linux学习之RPM包管理-rpm命令管理(十六)
  18. Unity3D中录制和输出wav文件
  19. laravel使用记录
  20. HDU 4585 平衡树Treap

热门文章

  1. ActiveMQ监听消息并进行转发,监听不同的mq服务器和不同的队列
  2. 洛谷 P4592: bzoj 5338: [TJOI2018]异或
  3. PHP 生成、识别二维码及安装相关扩展/工具
  4. js中this揭秘
  5. java基础59 JavaScript运算符与控制流程语句(网页知识)
  6. android入门问题--R文件丢失
  7. opencv之dft及mat类型转换
  8. Github中展示demo
  9. MySQL学习笔记:case when
  10. java遍历ftp文件夹下所有文件(或指定文件下的文件)