HDU-5801 可持久化Trie树

Up Sky,Mr.Zhu

Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 46    Accepted Submission(s): 14


Problem Description
Given a string S[0,...n-1],and the length of each palindrome substring in S is less than 20.

Define special string of a palindrome string STR[0,...,n-1] is STR[floor(n/2),...,n-1]

Given L,R and a string T, Query the number of palindrome strings, whose the prefix of special string is T, in S[L,...,R] 

ps:floor means the function in C++ language
(No relation between statement and title)
 

Input
There are severval cases,please peocess until EOF.
The first line contains string S.(1<=|S|<=1e5)
The second line is a number q means the number of querys.(1<=q<=1e5)
The next q lines,each line contains two numbers L,R and a string T.(1<=L<=R<=|S|,1<=|T|<=10)
All strings only contain 'a','b','c','d' and 'e'.
 

Output
For each query,you should output the number of palindrome strings which satisfied previous condition in a line.
 

Sample Input
  
  
bceaeedde 5 5 8 e 3 5 e 1 2 a 5 9 d 5 9 de
 

Sample Output
  
  
3 2 0 4 1
 

Author
UESTC
 

Source

题目链接:

题目大意:
定义一个回文串的特征串为其从中心到结尾的部分,给出一个字符串S,q次询问,每次询问以一个字符串t为特征串前缀落在区间L到R之间的回文串数量,S中回文串长度不会超过20。

解题思路:
先Manacher预处理,然后我们用Trie树来维护以每个位置为起始的特征串,注意到特征串的长度不会超过10,所以我们可以每次按一个长度建立可持久化Trie树,每次对所有询问的区间在线查询,更新答案,做10次即可。
为了不去考虑角码的运算,我将奇偶串分开讨论了,代码就显得有些冗余。最后要吐槽hdu谜一样的java内存机制,开始估计数组最大要开到10^6,结果MLE了,索性开到10^5枚举内存,居然神奇的AC了。

AC代码:
import java.io.*;
import java.util.*;

public class Main {
	static StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static int nextInt() throws IOException    
	{  
	    in.nextToken();    
	    return (int)in.nval;     
	}
	static String next() throws IOException    
	{  
	    in.nextToken();  
	    return in.sval;
	}
	static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
	static int n,m,len,sz,a;
	static char[] s;
	static char[] ss=new char[200005];
	static int[] pp=new int[200005];
	static int[] aa=new int[100005];
	static int[] bb=new int[100005];
	static int[] cc=new int[100005];
	static int[] rt=new int[100005];
	static int[] ans=new int[100005];
	static int[] cnt=new int[100005];
	static char[][] tt=new char[100005][];
	static int[][] ch=new int[100005][5];
	static void Manacher()
	{
		Arrays.fill(ss,'#');
		for(int i=0;i<n;i++)
			ss[i*2+2]=s[i];
		len=n*2+1;ss[0]='$';
		int max=0,id=0;
		for(int i=1;i<=len;i++)
		{
			if(max>i)
				pp[i]=Math.min(pp[id*2-i],max-i);
			else pp[i]=1;
			while(ss[i+pp[i]]==ss[i-pp[i]])
				pp[i]++;
			if(i+pp[i]>max) { max=i+pp[i];id=i;}
		}
	}
	static void insert(int a,int b,int l,int r)
	{
		int u=a,v=b,p;
		for(int i=l;i<=r;i++)
		{
			p=ss[i]-'a';
			for(int k=0;k<5;k++)
				ch[u][k]=ch[v][k];
			cnt[u]=cnt[v]+1;
			ch[u][p]=++sz;
			u=ch[u][p];v=ch[v][p];
		}
		cnt[u]=cnt[v]+1;
	}
	static int query(int a,int b,int k)
	{
		int u=a,v=b,p;
		for(int i=0;i<tt[k].length;i++)
		{
			p=tt[k][i]-'a';
			u=ch[u][p];v=ch[v][p];
		}
		return cnt[v]-cnt[u];
	}

	public static void main(String[] args) throws IOException {
		//Scanner in=new Scanner(System.in);
		while(in.nextToken()!=StreamTokenizer.TT_EOF)
		{
			s=in.sval.toCharArray();
			n=s.length;
			Manacher();
			for(int i=n;i>0;i--) ss[i]=s[i-1];
			m=nextInt();
			for(int i=1;i<=m;i++)
			{
				aa[i]=nextInt();bb[i]=nextInt();
				tt[i]=next().toCharArray();
				cc[i]=tt[i].length;
			}
			for(int i=1;i<=m;i++) ans[i]=0;
			for(int k=1;k<=10;k++)
			{
				sz=0;rt[0]=++sz;
				for(int i=1;i<=n;i++)
				{
					a=pp[i*2]/2;
					if(a>=k)
					{
						rt[i]=++sz;
						insert(rt[i],rt[i-1],i,i+k-1);
					}
					else rt[i]=rt[i-1];
				}
				for(int i=1;i<=m;i++)
				{
					if(cc[i]>k||k*2-1>bb[i]-aa[i]+1) continue;
					ans[i]+=query(rt[aa[i]+k-2],rt[bb[i]-k+1],i);
				}
				sz=0;rt[0]=++sz;
				for(int i=1;i<=n;i++)
				{
					a=pp[i*2-1]/2;
					if(a>=k)
					{
						rt[i]=++sz;
						insert(rt[i],rt[i-1],i,i+k-1);
					}
					else rt[i]=rt[i-1];
				}
				for(int i=1;i<=m;i++)
				{
					if(cc[i]>k||k*2>bb[i]-aa[i]+1) continue;
					ans[i]+=query(rt[aa[i]+k-1],rt[bb[i]-k+1],i);
				}
			}
			for(int i=1;i<=m;i++)
				out.println(ans[i]);
		}
		out.flush();
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值