您的位置:首页 > 其它

[BZOJ3238]-[Ahoi2013]差异-后缀自动姬

2018-01-18 12:28 393 查看

说在前面

感觉后缀自动姬真好玩hhhhh

今天分配任务,me要去讲小专题,然而感觉自己就没有什么专精的东西啊!

果然me还是太弱了

题目

BZOJ3238传送门

题面



输入输出格式

输入格式:

输入仅一行,包含一个字符串

输出格式:

当然是输出答案啦

解法

这题要用到一点parent树的性质,不过很简单YY一下就知道的

parent树实质上就是这个字符串的反前缀树,怎么理解呢,right集合就是右端点位置的集合,随着向左延伸的长度不断变长,right集合不断分裂,分裂到最后每个right集合都只有一个元素,这个元素就是原串的一个前缀。所以,如果把一个串倒过来建后缀自动姬,它的parent树实际上就是后缀树

那么对于这道题,前面的部分可以O(1)求,关键就是求各个后缀的最长公共前缀,然后这正好就是后缀树干的事情。于是我们对反串建立后缀自动姬,处理出parent树,然后dfs一遍parent树,每个节点的贡献就是它的各个儿子的 叶子节点个数 的乘积。于是这道题就做完了。

下面是自带大常数的代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

char ss[500005] ;
int N , id_c , head[1000005] , tp ;
long long ans ;
struct Node{
char cc ;
int len , id , siz ;
Node *ch[26], *par  ;
}w[1000005] , *tw = w , *root , *last ;
struct Path{
int pre , to ;
}p[1000005] ;

void In( const int &t1 , const int &t2 ){
p[++tp].pre = head[t1] ;
p[ head[t1] = tp ].to = t2 ;
}

void newNode( Node *&nd , char cc , int len ){
nd = ++tw ; nd->siz = 1 ;
nd->id = ++id_c , nd->cc = cc ;
nd->len = len ;
}

void Insert( const char &cc ){
Node *nd , *tmp = last ;
newNode( nd , cc , last->len + 1 ) ;
short id = cc - 'a' ;

for( ; tmp && !tmp->ch[id] ; tmp = tmp->par )
tmp->ch[id] = nd ;
if( !tmp ) nd->par = root ;
else{
if( tmp->ch[id]->len == tmp->len + 1 )
nd->par = tmp->ch[id] ;
else{
Node *B = tmp->ch[id] , *nB = ++ tw ;
*nB = *B ; nB->siz = 0 ;
nB->id = ++id_c , nB->len = tmp->len + 1 ; //Notice!!! 需要分配id
B->par = nd->par = nB ;
while( tmp && tmp->ch[id] == B ){
tmp->ch[id] = nB ;
tmp = tmp->par ;
}
}
}
last = nd ;
}

long long dfs( int u ){
long long siz = w[u].siz , tmp ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
tmp = dfs( v ) ;
ans -= siz * tmp * w[u].len * 2 ;
siz += tmp ;
}
return siz ;
}

void solve(){
ans = 1LL * ( N - 1 ) * ( N + 1 ) * N / 2 ;
for( Node *t = w + 1 ; t <= tw ; t ++ )
if( t->par ) In( t->par->id , t->id ) ;
for( int i = head[ root->id ] ; i ; i = p[i].pre )
dfs( p[i].to ) ;
printf( "%lld" , ans ) ;
}

int main(){
scanf( "%s" , ss + 1 ) ; N = strlen( ss + 1 ) ;
newNode( root , 0 , 0 ) ; last = root ;
for( int i = N ; i >= 1 ; i -- ) Insert( ss[i] ) ;
solve() ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: