Prefix
Time Limit: 2000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 474 Accepted Submission(s): 150
Problem Description
Alice gets N strings. Now she has Q questions to ask you. For each question, she wanna know how many different prefix strings between Lth and Rth strings. It's so easy right? So solve it!
Input
The input contains multiple test cases.
For each test case, the first line contains one integer N(1≤N≤100000) . Then next N lines contain N strings and the total length of N strings is between 1 and 100000. The next line contains one integer Q(1≤Q≤100000) . We define a specail integer Z=0. For each query, you get two integer L, R(0=<L,R<N). Then the query interval [L,R] is [min((Z+L)%N,(Z+R)%N)+1,max((Z+L)%N,(Z+R)%N)+1]. And Z change to the answer of this query.
For each test case, the first line contains one integer N(1≤N≤100000) . Then next N lines contain N strings and the total length of N strings is between 1 and 100000. The next line contains one integer Q(1≤Q≤100000) . We define a specail integer Z=0. For each query, you get two integer L, R(0=<L,R<N). Then the query interval [L,R] is [min((Z+L)%N,(Z+R)%N)+1,max((Z+L)%N,(Z+R)%N)+1]. And Z change to the answer of this query.
Output
For each question, output the answer.
Sample Input
3 abc aba baa 3 0 2 0 1 1 1
Sample Output
7 6 3
Author
ZSTU
Source
题目链接:
题目大意:
给出n个字符串,每次询问第L个字符串到第R个字符串中不同前缀的个数,强制在线。
解题思路:
之间有做过用Trie树哈希的题目,这个题其实就是用Trie给每个前缀一个值,这样就将一个字符串转化成了几个不同的数,再查询区间内不同数的个数就可以了,区间内不同数的个数用主席树来做。
比赛时用java写数组开到4e6就MLE了,赛后改了好几天过不了,只好向C++妥协。
AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = (int)4e6+10;
const int M = (int)1e5+10;
char s[M];
int n,sz,ct,pp,ans,m,a,b,L,R;
int aa[M],mm[M],last[M],lpos[M],rpos[M];
int rt[M],ll[N],rr[N],data[N],ch[M][26];
void insert()
{
int u=0,a,len=strlen(s);
for(int i=0;i<len;i++)
{
a=s[i]-'a';
if(ch[u][a]==0)
{
ch[u][a]=++sz;
for(int j=0;j<26;j++)
ch[sz][j]=0;
}
u=ch[u][a];
aa[++ct]=u;
}
}
void build(int l,int r,int k)
{
data[k]=0;
if(l==r) return;
int mid=(l+r)/2;
ll[k]=++pp;build(l,mid,ll[k]);
rr[k]=++pp;build(mid+1,r,rr[k]);
}
void updata(int a,int b,int k,int l,int r,int x)
{
data[a]=data[b]+x;
if(l==r) return;
int mid=(l+r)/2;
if(k<=mid)
{
rr[a]=rr[b];ll[a]=++pp;
updata(ll[a],ll[b],k,l,mid,x);
}
else
{
ll[a]=ll[b];rr[a]=++pp;
updata(rr[a],rr[b],k,mid+1,r,x);
}
}
int query(int a,int b,int k,int l,int r)
{
if(a<=l&&r<=b) return data[k];
int mid=(l+r)/2,res=0;
if(mid>=a) res+=query(a,b,ll[k],l,mid);
if(mid+1<=b) res+=query(a,b,rr[k],mid+1,r);
return res;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<26;i++)
ch[0][i]=0;
sz=ct=0;
for(int i=1;i<=n;i++)
{
scanf("%s",s);
lpos[i]=ct+1;
insert();
rpos[i]=ct;
}
for(int i=1;i<=sz;i++) mm[i]=N;
for(int i=ct;i>0;i--)
{
last[i]=mm[aa[i]];
mm[aa[i]]=i;
}
pp=0;
rt[ct+1]=++pp;build(1,ct,rt[ct+1]);
for(int i=ct;i>0;i--)
{
rt[i]=++pp;
updata(rt[i],rt[i+1],i,1,ct,1);
if(last[i]<N)
{
a=++pp;
updata(a,rt[i],last[i],1,ct,-1);
rt[i]=a;
}
}
scanf("%d",&m);ans=0;
while(m--)
{
scanf("%d%d",&a,&b);
L=min((a+ans)%n,(b+ans)%n)+1;
R=max((a+ans)%n,(b+ans)%n)+1;
ans=query(lpos[L],rpos[R],rt[lpos[L]],1,ct);
printf("%d\n",ans);
}
}
}