题目链接:点击查看
题目大意:给出 n 个字符串,再给出 m 次询问,每次询问需要输出区间 [ l , r ] 内的所有字符串有多少个不同的前缀,要求算法强制在线
题目分析:统计字符串的前缀,不难想到借助字典树实现,再将问题简化为在线求区间 [ l , r ] 内不同数字的个数,这就是主席树的基本应用了,两个模板搭配起来就是这个问题的答案了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
/*主席树*/
struct Node
{
int l,r;
int sum;
}tree[N*40];
int cnt,root[N];
void change(int pos,int &k,int l,int r,int val)
{
tree[cnt++]=tree[k];
k=cnt-1;
tree[k].sum+=val;
if(l==r)
return;
int mid=l+r>>1;
if(pos<=mid)
change(pos,tree[k].l,l,mid,val);
else
change(pos,tree[k].r,mid+1,r,val);
}
int query(int rt,int pos,int l,int r)
{
if(l==r)
return tree[rt].sum;
int mid=l+r>>1;
if(pos<=mid)
return tree[tree[rt].r].sum+query(tree[rt].l,pos,l,mid);
else
return query(tree[rt].r,pos,mid+1,r);
}
/*主席树*/
/*字典树*/
string s[N];
int k;
int trie[N][26];//储存每一条边 trie[节点数][字符数]
int pre[N];//判断某一个字符串是否出现过
int newnode()
{
k++;
for(int i=0;i<26;i++)
trie[k][i]=0;
pre[k]=0;
return k;
}
void insert(string& s)//插入
{
int pos=0;
for(int i=0;i<s.size();i++)
{
int to=s[i]-'a';
if(!trie[pos][to])
trie[pos][to]=newnode();
pos=trie[pos][to];
}
}
void search(string& s,int id,int n)//查找
{
int pos=0;
for(int i=0;i<s.size();i++)
{
int to=s[i]-'a';
pos=trie[pos][to];
if(pre[pos])
change(pre[pos],root[id],1,n,-1);
change(id,root[id],1,n,1);
pre[pos]=id;
}
}
/*字典树*/
void init()
{
root[0]=0;
tree[0].l=tree[0].r=tree[0].sum=0;
cnt=1;
k=-1;
newnode();
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n;
while(scanf("%d",&n)!=EOF)
{
init();
for(int i=1;i<=n;i++)
{
cin>>s[i];
insert(s[i]);
}
for(int i=1;i<=n;i++)
{
root[i]=root[i-1];
search(s[i],i,n);
}
int m;
scanf("%d",&m);
int ans=0;
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
l=(l+ans)%n+1;
r=(r+ans)%n+1;
if(l>r)
swap(l,r);
printf("%d\n",ans=query(root[r],l,1,n));
}
}
return 0;
}