分析:这个题和spoj的d_query是一个题,那个是求一段区间里有多少个不同的数字,这里是统计有多少个不同的前缀
用字典树进行判重,(和查询不同的数字一样)对于每个不同的前缀,只保留它最后一次出现的序号
然后强制在线,用主席树就好了
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long LL; const int N = 1e5+5; const int mod = 1e9+7; int p[N][26],cnt,last[N],n,q; char s[N]; struct Node{ int l,r,v; }o[40*N]; int root[N],sz; void add(int &rt,int l,int r,int pos,int t){ o[++sz]=o[rt],rt=sz; o[rt].v+=t; if(l==r)return; int m=(l+r)>>1; if(pos<=m)add(o[rt].l,l,m,pos,t); else add(o[rt].r,m+1,r,pos,t); } int query(int rt,int l,int r,int x,int y){ if(x<=l&&r<=y) return o[rt].v; int m=(l+r)>>1; int ans=0; if(x<=m)ans+=query(o[rt].l,l,m,x,y); if(y>m)ans+=query(o[rt].r,m+1,r,x,y); return ans; } int newnode(){ ++cnt; memset(p[cnt],-1,sizeof(p[cnt])); return cnt; } void insert(int cur){ int now=0,tr=root[cur-1],len=strlen(s+1); for(int i=1;i<=len;++i){ int v=s[i]-'a'; if(p[now][v]==-1){ p[now][v]=newnode(); now=p[now][v]; last[now]=cur; add(tr,1,n,cur,1); } else{ now=p[now][v]; add(tr,1,n,last[now],-1); add(tr,1,n,cur,1);last[now]=cur; } } root[cur]=tr; } int main(){ while(~scanf("%d",&n)){ cnt=-1;newnode();sz=0; o[0].l=o[0].r=o[0].v=0; for(int i=1;i<=n;++i){ scanf("%s",s+1); insert(i); } int z=0,l,r; scanf("%d",&q); while(q--){ scanf("%d%d",&l,&r); l=(l+z)%n+1;r=(r+z)%n+1; if(l>r)swap(l,r); printf("%d ",z=query(root[r],1,n,l,r)); } } return 0; }