​HDU5790 Prefix​

Mean

给定\(n\)个字符串,\(m\)次询问,每次询问第\([l,r]\)个字符串中的一共有多少种不同的前缀.强制在线.\(n,m<=1e5\).

Sol

主席树+\(Trie\)。

考虑抽象化,就是将所有前缀依次排开,给相同的前缀标上相同的权值,做一遍主席树求区间内不同数的个数。

如何给相同的前缀标上相同的权值?

考虑用\(n\)个字符串建出\(Trie\),那么完全可以用一个\(Trie\)上一个节点的标号来表示相同的前缀。当然,也可以用\(Hash\)来解决,不过正确率无法保证\(100\)。

最后就是主席树的操作了,查询区间\([st[l],ed[r]]\)中有多少个不同的树即可。

如果这题不强制在线,还有莫队或者树状数组这类的经典离线做法。

Code

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define lowbit(x) (x&(-x))
#define debug(x) cout<<#x<<" :"<<x<<endl
#define debug1(x) cout<<#x<<" :"<<x<<" "
#define mid ((l+r)>>1)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N=2e5+20;
const int MAX=10000007;
inline int read() {
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0',c=getchar();}
return x*f;
}

inline void out(int x) {
if(x>9) out(x/10);
putchar(x%10+'0');
}
int q[N];
ll ary[N];
ll kep[N];char s[N];

struct trie{
int tr[N*20][26];
int tot;
int rt;
void insert(char s[],int lens){
int pos=rt;
for(int i=1;i<=lens;++i){
int v = s[i]-'a';
if(!tr[pos][v])tr[pos][v]=++tot;
pos = tr[pos][v];
}
}
void query(char s[],int lens){
int pos=rt;
int ans=0;
for(int i=1;i<=lens;++i){
int v = s[i]-'a';
pos=tr[pos][v];
kep[i]=pos;
}
}
void init(){
rep(i,0,tot){
rep(j,0,25)
tr[i][j]=0;
}
tot=rt=0;
}
}tt;

int n,m;

int st[N],ed[N];
int last[N];
int vis[N];
int tot=0;
struct node{
int ls,rs;
int sum;
}tr[N*40];
int rt[N];

int build(int l,int r){
int p =++tot;
tr[p].sum = 0;
if(l==r){
return p;
}
tr[p].ls = build(l,mid);
tr[p].rs = build(mid+1,r);

return p;
}

int update(int pos,int loc,int l,int r){
int p =++tot;
tr[p]=tr[pos];
tr[p].sum++;
if(l==r){
return p;
}
if(loc<=mid)tr[p].ls = update(tr[pos].ls,loc,l,mid);
else tr[p].rs = update(tr[pos].rs,loc,mid+1,r);

return p;
}
int query(int now,int las,int l,int r,int L,int R){
if(L<=l&&r<=R){
return tr[now].sum-tr[las].sum;
}
int ans=0;
if(L<=mid)ans = ans+query(tr[now].ls,tr[las].ls,l,mid,L,R);
if(R>mid)ans = ans+query(tr[now].rs,tr[las].rs,mid+1,r,L,R);
return ans;
}
int main(){
while(scanf("%d",&n)!=EOF){
int con=0;
tt.init();
rep(i,1,n){
st[i]=ed[i]=0;
scanf("%s",s+1);
int lens=strlen(s+1);

tt.insert(s,lens);
tt.query(s,lens);
rep(j,1,lens){
ary[++con] = kep[j];
if(j==1)st[i]=con;
if(j==lens)ed[i]=con;
}
}
rep(i,1,con){
kep[i]=ary[i];
rt[i]=0;
}
rep(i,0,tot)tr[i].ls=tr[i].rs=tr[i].sum=0;
tot=0;
rt[0] = build(0,con);
memset(last,0,sizeof(last));

rep(i,1,con){
rt[i] = update(rt[i-1],last[ary[i]],0,con);
last[ary[i]]=i;
}
int Z=0;
scanf("%d",&m);
rep(i,1,m){
int L,R,nl,nr;
scanf("%d%d",&L,&R);
nl = min((Z+L)%n,(Z+R)%n)+1;
nr = max((Z+L)%n,(Z+R)%n)+1;
int ans =query(rt[ed[nr]],rt[st[nl]-1],0,con,0,st[nl]-1);
printf("%d\n", ans);
Z=ans;
}

}
return 0;
}
/*
3
abc
aba
baa
3
0 2
0 1
1 1
*/