[2017.7.6]回文树
1 const int MAXN = 100005 ; 2 const int N = 26 ; 3 4 struct Palindromic_Tree{ 5 int next[MAXN][N] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成 6 int fail[MAXN] ;//fail指针,失配后跳转到fail指针指向的节点 7 8 int cnt[MAXN] ; 9 int num[MAXN] ; 10 int len[MAXN] ;//len[i]表示节点i表示的回文串的长度 11 int S[MAXN] ;//存放添加的字符 12 int last ;//指向上一个字符所在的节点,方便下一次add 13 int n ;//字符数组指针 14 int p ;//节点指针 15 16 int newnode ( int l ) {//新建节点 17 for ( int i = 0 ; i < N ; ++ i ) next[p][i] = 0 ; 18 cnt[p] = 0 ; 19 num[p] = 0 ; 20 len[p] = l; 21 return p ++ ; 22 } 23 24 void init () {//初始化 25 p = 0; 26 newnode ( 0 ) ; 27 newnode ( -1 ) ; 28 last = 0; 29 n = 0; 30 S[n] = -1 ;//开头放一个字符集中没有的字符,减少特判 31 fail[0] = 1 ; 32 } 33 34 int get_fail ( int x ) {//和KMP一样,失配后找一个尽量最长的 35 while ( S[n - len[x] - 1] != S[n] ) x = fail[x] ; 36 return x; 37 } 38 39 void add ( int c ) { 40 c -= 'a' ; 41 S[++ n] = c; 42 int cur = get_fail ( last ) ;//通过上一个回文串找这个回文串的匹配位置 43 if ( !next[cur][c] ) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串 44 int now = newnode ( len[cur] + 2 ) ;//新建节点 45 fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自动机一样建立fail指针,以便失配后跳转 46 next[cur][c] = now ; 47 num[now] = num[fail[now]] + 1; 48 } 49 last = next[cur][c]; 50 cnt[last] ++ ; 51 } 52 void count () { 53 for ( int i = p - 1 ; i >= 0 ; -- i ) cnt[fail[i]] += cnt[i] ; 54 //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的回文子串! 55 } 56 };
From:blog.csdn.net/u013368721/article/details/42100363
注意:第46行的代码不能缩到和44行的那一行,因为可能get_fail(fail[cur])指向的还是自己,这样自己的儿子就多了一个,自己的fail就指向了自己,会死循环。