1. 程式人生 > >HDU - 5421:Victor and String (回文樹,支持首尾插入新字符)

HDU - 5421:Victor and String (回文樹,支持首尾插入新字符)

std ref == bsp ner efi hdu fail containe

Sample Input
6
1 a
1 b
2 a
2 c
3
4
8
1 a
2 a
2 a
1 a
3
1 b
3
4
Sample Output
4
5
4
5
11

題意:多組輸入,開始字符串為空,支持4中操作: 1,在字符串首加字符; 2,在字符串尾加字符; 3,查詢字符串不同本質的回文串個數; 4,查詢回文串個數總和

思路:因為支持首尾加入,所以和常規的回文樹有些不同。 參考了YYB的博客。 發現首尾互相影響,當且僅當整個字符串是回文串。 其他情況兩頭正常加即可。

#include<bits/stdc++.h>
#define
ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) #define rep2(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=100010; struct PAT { struct node{ int len,num,fail,son[26]; }t[maxn]; int n,tot,s[maxn<<1],L,R,suf,pre; ll ans; void init() { memset(t,
0,sizeof(t)); memset(s,-1,sizeof(s)); tot=1; L=100000; R=L-1; suf=pre=0; ans=0; t[1].len=-1; t[0].fail=t[1].fail=1; } void add(int c,int n,int &last,int op){ int p=last; s[n]=c; while(s[n]!=s[n-op-op*t[p].len]) p=t[p].fail; if(!t[p].son[c]){
int v=++tot,k=t[p].fail; while(s[n]!=s[n-op*t[k].len-op]) k=t[k].fail; t[v].fail=t[k].son[c]; t[v].len=t[p].len+2; t[v].num=t[t[v].fail].num+1; t[p].son[c]=v; } last=t[p].son[c]; ans+=t[last].num; if(t[last].len==R-L+1) suf=pre=last; } }T; int main() { int N; while(~scanf("%d",&N)){ T.init(); int opt; rep(i,1,N){ scanf("%d",&opt); char s[3]; if(opt==1){ scanf("%s",s); T.add(s[0]-a,--T.L,T.pre,-1); } else if(opt==2){ scanf("%s",s); T.add(s[0]-a,++T.R,T.suf,1); } else if(opt==3) printf("%d\n",T.tot-1); else printf("%lld\n",T.ans); } } return 0; }

HDU - 5421:Victor and String (回文樹,支持首尾插入新字符)