HDU 5394 Trie in Tina Town

Problem Description
Tina Town is a friendly place. People there care about each other.

A trie which was planted by the first mayor of Tina Town grows in the center of the town.

We define a palindrome substring in a trie a string that is a suffix of a string which the path from the root to any node represents and the string is a palindrome. Two palindromes are different if and only if their positions are different. Now, Tina wants to know the sum of the length of all palindrome substrings. Tina didn’t know the answer so she asked you to find out the answer for her.
 

Input
The first line contains a integer – number of cases
For each case, the first line is an integer  N  representing the number of nodes in trie except the root.
The following  N  lines contains a letter between  a  and  d  – the letter that node  n[i]  stores and a number  f[i]  – the index of  n[i] ’s father. It’s guaranteed that  fa[i]i . If  fa[i]=0  n[i] is the root.
T10,N2106
 

Output
The first line contains a integer – number of cases
For each case, the first line is an integer  N  representing the number of nodes in trie except the root.
The following  N  lines contains a letter between  a  and  d  – the letter that node  n[i]  stores and a number  f[i]  – the index of  n[i] ’s father. It’s guaranteed that  fa[i]i . If  fa[i]=0  n[i] is the root.
T10,N2106
 

Sample Input
  
  
2 5 a 0 a 1 a 2 b 1 b 4 5 a 0 a 1 a 2 b 1 a 4
 

Sample Output
  
  
14 15
Hint
The first test case is a trie like this: aaa *1 -> 3 aa *2 -> 4 a *3-> 3 b *2-> 2 bb *1- > 2 3+4+3+2+2 = 14 The second test case: aaa *1 -> 3 aba *1 -> 3 a *4 -> 4 b *1 -> 1 aa *2 -> 4 3+3+4+1+4 = 15 If the stack size is too small, you can submit it in C++ and add ‘#pragma comment(linker, "/STACK:102400000,102400000”)’ at the head of your program. Large input, recommend to use fast I/O.

回文树的应用,这里的操作有加入一个字母和删除一个字母,以及计算一个前缀对应的全部后缀回文串长度和,可以直接在回文树上统计。

#pragma comment(linker, "/STACK:102400000,102400000")
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<bitset>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<functional>
using namespace std;
typedef long long LL;
const int low(int x) { return x&-x; }
const int INF = 0x7FFFFFFF;
const int mod = 1e9 + 7;
const int maxn = 2e6 + 10;
int T, n, ft[maxn], nt[maxn], x;
char s[maxn], ch;
LL ans;

struct PalindromicTree
{
	const static int maxn = 2e6 + 10;
	const static int size = 4;
	int next[maxn][size], sz, tot;
	int fail[maxn], len[maxn], last[maxn], pre[maxn];
	LL cnt[maxn];
	char s[maxn];
	void clear()
	{
		len[1] = -1; len[2] = 0;
		fail[1] = fail[2] = 1;
		cnt[1] = cnt[2] = tot = 0;
		last[0] = (sz = 3) - 1;
		memset(next[1], 0, sizeof(next[1]));
		memset(next[2], 0, sizeof(next[2]));
	}
	int Node(int length)
	{
		memset(next[sz], 0, sizeof(next[sz]));
		len[sz] = length;      return sz;
	}
	int getfail(int x)
	{
		while (s[tot] != s[tot - len[x] - 1]) x = fail[x];
		return x;
	}
	LL add(char pos)
	{
		int x = (s[++tot] = pos) - 'a', y = getfail(last[tot - 1]);
		if (next[y][x]) { last[tot] = next[y][x]; pre[tot] = 0; }
		else {
			last[tot] = next[y][x] = Node(len[y] + 2);
			pre[tot] = y;
			fail[sz] = len[sz] == 1 ? 2 : next[getfail(fail[y])][x];
			cnt[sz] = cnt[fail[sz]] + len[sz];        ++sz;
		}
		return cnt[last[tot]];
	}
	void del(char pos)
	{
		int x = pos - 'a';
		if (pre[tot])
		{
			next[pre[tot]][x] = 0;
			--sz;
		}
		--tot;
	}
}solve;

inline int get()
{
	while ((ch = getchar()) < '0' || ch > '9');
	int x = ch - '0';
	while ((ch = getchar()) >= '0' && ch <= '9') x = x * 10 + ch - '0';
	return x;
}

void dfs(int x)
{
	for (int i = ft[x]; i != -1; i = nt[i])
	{
		ans += solve.add(s[i]);
		dfs(i);
		solve.del(s[i]);
	}
}

int main()
{
	scanf("%d", &T);
	while (T--)
	{
		solve.clear();
		scanf("%d", &n);
		for (int i = 0; i <= n; i++) ft[i] = -1;
		for (int i = 1; i <= n; i++)
		{
			//while ((s[i] = getchar()) < 'a' || ch > 'd');
			//x = get(); nt[i] = ft[x];    ft[x] = i;
			scanf("%s%d", s + i, &x);
			nt[i] = ft[x];    ft[x] = i;
		}
		dfs(ans = 0);
		printf("%lld\n", ans);
	}
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值