hdu5421 Victor and String 回文树(前后插入)

题目传送门

题意:对一个字符串支持四种操作,前插入字符,后插入字符,询问本质不同的回文串数量和所有回文串的数量。

思路:

  就是在普通回文树的基础上,维护suf(最长回文后缀)的同时再维护一个pre(最长回文前缀),即可完成以上操作。

代码基本是学习巨佬yyb

#pragma GCC optimize (2)
#pragma G++ optimize (2)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
#include<cstdio>
#include<vector>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,b,a) for(int i=b;i>=a;i--)
#define clr(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pii pair<int,int >
using namespace std;
typedef long long ll;
ll rd()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int maxn=300010;
int size[maxn];
char s[maxn];
int l,r,pre,suf,n; 
ll ans;
struct Palindromic_Tree
{
    struct Node
    {
        int son[26];
        int ff,len,dep;
    }t[maxn];
    int last,tot;
    void init()
    {
        l=1e5,r=l-1;
        tot=0;
        clr(s,'\0');
        clr(t,0);
        t[++tot].len=-1;
        t[0].ff=t[1].ff=1;
    }
    void extend(int c,int n,int &last,int op)
    {
        int p=last;
        while(s[n-op*t[p].len-op]!=s[n])p=t[p].ff;
        if(!t[p].son[c])
        {
            int v=++tot,k=t[p].ff;
            t[v].len=t[p].len+2;
            while(s[n-op*t[k].len-op]!=s[n])k=t[k].ff;
            t[v].ff=t[k].son[c];    
            t[p].son[c]=v;
            t[v].dep=t[t[v].ff].dep+1;
        }
        last=t[p].son[c];
        ans+=t[last].dep;
        if(t[last].len==r-l+1)pre=suf=last; 
    }
}a;
int main(){
    while(cin>>n){
        a.init();
        ans=0;
        while(n--){
            int op=rd();
            if(op<=2){
                char c=getchar();
                if(op==1)s[--l]=c,a.extend(c-97,l,pre,-1);
                else s[++r]=c,a.extend(c-97,r,suf,1);
            }else if(op==3)printf("%d\n",a.tot-1);
            else printf("%lld\n",ans);
        }
    }
}

 

posted @ 2019-09-20 14:37  光芒万丈小太阳  阅读(281)  评论(0编辑  收藏  举报