题目链接:hdu_5790_Prefix
题意:
给你n个字符串,字符串总长度不超过10W,然后给你一个区间,问你这个区间的字符串不相同的前缀有多少个。
题解:
由于z与上一个答案有关,所以强制在线,区间询问可以用主席树搞搞。
不同前缀的话,我们可以用一个trie来记录每一个节点的最晚出现时间,也就代表了这个前缀最晚出现的时间,然后保存到对应的主席树中。
这样就转换为询问区间不大于l的数有多少个。
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 5 const int N=1e5+7; 6 char s[N]; 7 int root[N],tot,n,q; 8 struct node{int l,r,sum;}T[25*N]; 9 10 void update(int &x,int y,int pos,int l=1,int r=n) 11 { 12 T[++tot]=T[y],T[tot].sum++,x=tot; 13 if(l==r)return; 14 int m=l+r>>1; 15 if(pos<=m)update(T[x].l,T[y].l,pos,l,m); 16 else update(T[x].r,T[y].r,pos,m+1,r); 17 } 18 19 int query(int x,int y,int k,int l=1,int r=n) 20 { 21 if(l==r)return T[x].sum-T[y].sum; 22 int m=l+r>>1; 23 if(k<=m)return query(T[x].l,T[y].l,k,l,m); 24 else return T[T[x].l].sum-T[T[y].l].sum+query(T[x].r,T[y].r,k,m+1,r); 25 } 26 27 struct Trie{ 28 int tr[N][26],tot,mx[N]; 29 void nd(){mx[++tot]=0,memset(tr[tot],0,sizeof(tr[tot]));} 30 void init(){tot=-1,nd();} 31 void insert(char *s,int time) 32 { 33 int t1=root[time-1],t2; 34 for(int i=0,x=0;s[i]!='\0';i++) 35 { 36 if(!tr[x][s[i]-'a']) 37 { 38 nd(),update(t2,t1,1); 39 t1=t2,tr[x][s[i]-'a']=tot,mx[tot]=time,x=tot; 40 } 41 else update(t2,t1,mx[x=tr[x][s[i]-'a']]+1),t1=t2,mx[x]=time; 42 } 43 root[time]=t1; 44 } 45 }trie; 46 47 void init(){tot=0;trie.init();} 48 49 int main() 50 { 51 while(~scanf("%d",&n)) 52 { 53 init(); 54 F(i,1,n)scanf("%s",s),trie.insert(s,i); 55 scanf("%d",&q); 56 int l,r,z=0; 57 F(i,1,q) 58 { 59 scanf("%d%d",&l,&r); 60 l=(z+l)%n+1,r=(z+r)%n+1; 61 if(l>r)l^=r,r^=l,l^=r; 62 printf("%d\n",z=query(root[r],root[l-1],l)); 63 } 64 } 65 return 0; 66 }