hdu 5421 回文树

Victor and String

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/262144 K (Java/Others)
Total Submission(s): 56    Accepted Submission(s): 25


Problem Description
Victor loves to play with string. He thinks a string is charming as the string is a palindromic string.

Victor wants to play  n  times. Each time he will do one of following four operations.

Operation 1 : add a char  c  to the beginning of the string.

Operation 2 : add a char  c  to the end of the string.

Operation 3 : ask the number of different charming substrings.

Operation 4 : ask the number of charming substrings, the same substrings which starts in different location has to be counted.

At the beginning, Victor has an empty string.
 

Input
The input contains several test cases, at most  5  cases.

In each case, the first line has one integer  n  means the number of operations.

The first number of next  n  line is the integer  op , meaning the type of operation. If  op = 1  or  2 , there will be a lowercase English letters followed.

1n100000 .
 

Output
For each query operation(operation 3 or 4), print the correct answer.
 

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
 

Source
 

Recommend
hujie   |   We have carefully selected several similar problems for you:   5426  5425  5424  5423  5422 

主要处理前后同时插入字符串较为麻烦。

这里维护两个值:当前插入形成的字符串的最长回文前缀,当前插入形成的字符串的最长回文后缀,我的代码里用last[0]和last[1]表示

每次向前插入时,通过最长回文前缀来寻找它的父亲,向后插入时,通过最长回文后缀来寻找它的父亲。


#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
#include <string>
#include <queue>

#define M 110
#define N 150000
using namespace std;

class Node
{
public:
    int next[30], pre, num, len, preNum;
    void init(int _len)
    {
        memset(next, 0, sizeof next);
        pre = 0;
        num = 0;
        len = _len;
        preNum = 0;
    }
};
Node node[N];

class PaliTree
{
public:
    int cnt, str[N*3], o, root0, root1, r, l, last[2];
    long long paliSum;
    int newNode(int _len)
    {
        node[++cnt].init(_len);
        return cnt;
    }
    void init(int _n)
    {
        o = _n;
        cnt = -1;
        root0 = newNode(0);
        root1 = newNode(-1);
        last[0] = last[1] = root0;
        l = o; r = o-1;
        str[l-1] = str[r+1] = -1;
        node[root0].pre = root1;
        paliSum = 0;
    }
    int getFail(int p, int dir)
    {
        if(dir == 1)
        {
            for(; str[r-node[p].len-1] != str[r]; p = node[p].pre);
        }
        else
        {
            for(; str[l+node[p].len+1] != str[l]; p = node[p].pre);
        }
        return p;
    }
    void extend(char _ch, int dir) // dir 为0 向左插入
    {
        int ch = _ch-'a';
        if(dir == 0)
        {
            str[--l] = ch;
            str[l-1] = -1;
        }
        else
        {
            str[++r] = ch;
            str[r+1] = -1;
        }
        int cur = getFail(last[dir], dir);
        int nxt = node[cur].next[ch];
        if(!nxt)
        {
            nxt = newNode(node[cur].len+2);
            node[nxt].pre = node[getFail(node[cur].pre, dir)].next[ch];
            node[nxt].preNum = node[node[nxt].pre].preNum+1;
            node[cur].next[ch] = nxt;
        }
        last[dir] = nxt;
        if(dir == 0 && l+node[nxt].len-1 == r)
        {
            last[dir^1] = nxt;
        }
        else if(dir == 1 && r-node[nxt].len+1 == l)
        {
            last[dir^1] = nxt;
        }
        node[nxt].num++;
        paliSum += node[nxt].preNum;
    }
    int query1()
    {
        return cnt-1;
    }
    long long query2()
    {
        return paliSum;
    }
};

PaliTree tree;
int main()
{
	//freopen("C:\\Users\\zfh\\Desktop\\in.txt", "r", stdin);
    int q;
    while(scanf("%d", &q) != -1)
    {
        int type;
        char ch;
        tree.init(150000);
        for(int i = 0; i < q; i++)
        {
            scanf("%d", &type);
            if(type == 1)
            {
                scanf(" %c", &ch);
                tree.extend(ch, 0);
            }
            else if(type == 2)
            {
                scanf(" %c", &ch);
                tree.extend(ch, 1);
            }
            else if(type == 3)
            {
                printf("%d\n", tree.query1());
            }
            else printf("%I64d\n", tree.query2());
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值