码迷,mamicode.com
首页 > 其他好文 > 详细

Gym - 101806Q:QueryreuQ(第一次写回文树)

时间:2019-02-05 18:08:05      阅读:232      评论:0      收藏:0      [点我收藏+]

标签:mem   eof   out   substr   ali   ESS   else   输入   一个   

A string is palindrome, if the string reads the same backward and forward. For example, strings like "a", "aa", "appa", "queryreuq" are all palindromes.

For given empty string S, you should process following two queries :

  1. Add a lower case alphabet at the back of S.
  2. Remove a character at the back of S.

After processing a query, you should count the number of palindrome substring in S. For string S and integers i,  j (1 ≤ i ≤ j ≤ |S|), 技术图片 represents a substring from ith to jth character of S. You should print out the number of integer pairs (i,  j) where 技术图片 is palindrome.


Input

Input consists of two lines.

In the first line, Q, the number of queries is given. (1 ≤ Q ≤ 10, 000)

In the second line, the query is given as string of length Q. ith character Ki denotes the ith query.

Ki is ‘-‘ or lower case alphabet (‘a‘, ‘b‘, ..., ‘z‘) (without quotes).

If the character is ‘-‘, you should remove a character at the back of S. If the character is lower case alphabet, you should add a character Ki at the back of S.

It is guaranteed that length of S is always positive after the query.

Output

Print out Q space-separated integers in the first line. i-th integer should be the answer of the ith query.

Example
Input
17
qu-uer-ryr-reu-uq
Output
1 2 1 2 3 4 3 4 5 7 5 7 9 11 9 11 13 

题意:现在有一个空的字符串S,S每次在末尾添加一个字符,或者删去末尾的字符(输入‘-‘号表示)。现在让你求每次操作后字符串S的回文串个数。

思路:mad,队友写了一发回文树,但是他是每次操作都暴力建树,暴力求的,所以为了在线求而不是每次重新建树,我还现学了一下回文树,挺简单的。

就是每次fail指针跑就完事了。 比后缀自动机好理解多了。 那么这个题,每次我们加入一个字符,那就加到回文树里,如果删去,则在fail链上的所有点都-1,如果-1后变为0,则删去那个点(sz标记为-1)。

但是在全部都是aaaaaaa...这种情况下,复杂度还是有点高,和暴力的复杂度差不多,复杂度小于(N^2)/4,不过N为10000可以过。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=10010;
char c[maxn],s[maxn]; int fcy[maxn],pos[maxn];
struct Palindromic_Tree
{
    struct Node
    {
        int son[26];
        int fail,len;
    }t[maxn];
    int last,tot,sz[maxn];
    void init()
    {
        memset(sz,-1,sizeof(sz));
        t[++tot].len=-1; //-1是因为后面找fail是时候可以break
        t[0].fail=t[1].fail=1; //奇偶两棵树
    }
    int del(int Now)
    {
        int res=0;
        while(Now>1){
            if(sz[Now]==-1) continue;
            if(sz[Now]==1) sz[Now]=-1;
            else sz[Now]--;
            res++; Now=t[Now].fail;
        } return res;
    }
    void add(int c,int n)
    {
        int p=pos[n-1];
        while(s[n-t[p].len-1]!=s[n]) p=t[p].fail;
        if(!t[p].son[c])
        {
            int v=++tot,k=t[p].fail;
            t[v].len=t[p].len+2;
            while(s[n-t[k].len-1]!=s[n]) k=t[k].fail;
            t[v].fail=t[k].son[c];
            t[p].son[c]=v;
            sz[v]=0;
        }
        last=t[p].son[c];
        int Now=last,res=0;
        while(Now>1){
            if(sz[Now]!=-1) sz[Now]++,res++;
            else sz[Now]=1,res++;
            Now=t[Now].fail;
        }
        fcy[n]=res; pos[n]=last;
    }
}T;
int main()
{
    T.init(); int N,L=0,ans=0;
    scanf("%d%s",&N,c+1);
    pos[0]=1;
    rep(i,1,N){
        if(c[i]==-){
            ans-=T.del(pos[L]); L--;
        }
        else {
            L++; s[L]=c[i];
            T.add(c[i]-a,L);
            ans+=fcy[L];
        }
        printf("%d ",ans);
    }
    return 0;
}

 

Gym - 101806Q:QueryreuQ(第一次写回文树)

标签:mem   eof   out   substr   ali   ESS   else   输入   一个   

原文地址:https://www.cnblogs.com/hua-dong/p/10352859.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!