http://acm.hdu.edu.cn/showproblem.php?pid=5790
查询区间内不同字符串前缀数量 且字符串总长度不超1e5 可以想到主席树在线或线段树离线 又因为题目强制在线 所以主席树搞一搞 具体就是把一个长度为l的字符串中每一个前缀都哈希为一个数 总共l个数 这样查询多少不同字符串就转换为查询多少不同数
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll unsigned long long
const ll gou=137;
struct node
{
int l;
int r;
int val;
};
node tree[4000010];
ll ary[100010],tmp[100010];
int root[200010],mp[100010],sum[100010];
char ch[100010];
int n,q,tot,len,num;
int build(int l,int r)
{
int cur,m;
cur=num++;
tree[cur].l=0,tree[cur].r=0,tree[cur].val=0;
if(l==r) return cur;
m=(l+r)/2;
tree[cur].l=build(l,m);
tree[cur].r=build(m+1,r);
return cur;
}
int update(int rot,int tar,int val,int l,int r)
{
int cur,m;
cur=num++;
tree[cur]=tree[rot];
tree[cur].val+=val;
if(l==r) return cur;
m=(l+r)/2;
if(tar<=m) tree[cur].l=update(tree[rot].l,tar,val,l,m);
else tree[cur].r=update(tree[rot].r,tar,val,m+1,r);
return cur;
}
int query(int rot,int pl,int pr,int l,int r)
{
int res,m;
if(pl<=l&&r<=pr) return tree[rot].val;
res=0,m=(l+r)/2;
if(pl<=m) res+=query(tree[rot].l,pl,pr,l,m);
if(pr>m) res+=query(tree[rot].r,pl,pr,m+1,r);
return res;
}
int main()
{
ll val;
int i,j,l,p,tpl,tpr,pl,pr,ans;
while(scanf("%d",&n)!=EOF)
{
tot=0;
for(i=1;i<=n;i++)
{
scanf("%s",ch);
val=0,l=strlen(ch);
sum[i]=sum[i-1]+l;
for(j=0;j<l;j++)
{
val*=gou;
val+=ch[j];
ary[++tot]=val;
tmp[tot]=ary[tot];
}
}
sort(tmp+1,tmp+tot+1);
len=unique(tmp+1,tmp+tot+1)-tmp-1;
memset(mp,0,sizeof(mp));
num=0;
root[0]=build(1,tot);
for(i=1;i<=tot;i++)
{
p=lower_bound(tmp+1,tmp+len+1,ary[i])-tmp;
if(mp[p]==0)
{
root[i]=update(root[i-1],i,1,1,tot);
}
else
{
root[i]=update(root[i-1],mp[p],-1,1,tot);
root[i]=update(root[i],i,1,1,tot);
}
mp[p]=i;
}
ans=0;
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&tpl,&tpr);
pl=min((ans+tpl)%n,(ans+tpr)%n)+1;
pr=max((ans+tpl)%n,(ans+tpr)%n)+1;
ans=query(root[sum[pr]],sum[pl-1]+1,sum[pr],1,tot);
printf("%d\n",ans);
}
}
return 0;
}