BZOJ3483 : SGU505 Prefixes and suffixes(询问在线版)

将每个串正着插入Trie A中,倒着插入Trie B中。

并求出每个串在A,B中的dfs序。

每次查询等价于查询在A中dfs序在[la,ra]之间,在B中dfs序在[lb,rb]之间的串的个数,用主席树维护即可。

 

#include<cstdio>
const int S=2000010,N=2010,M=N*22;
char s[S],ch;
int n,m,i,j,k,posa[N],posb[N],g[S],v[N],nxt[N],ed,la,lb,ra,rb,ans;
inline void read(){
  while(!(((ch=getchar())>='a')&&(ch<='z')));
  s[k=1]=(ch-'a'+ans)%26;
  while(((ch=getchar())>='a')&&(ch<='z'))s[++k]=(ch-'a'+ans)%26;
}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
struct Trie{
int tot,son[S][26],st[S],en[S],dfn;
inline int ins0(){
  int x=0;
  for(int i=1;i<=k;i++){
    if(!son[x][s[i]])son[x][s[i]]=++tot;
    x=son[x][s[i]];
  }
  return x;
}
inline int ins1(){
  int x=0;
  for(int i=k;i;i--){
    if(!son[x][s[i]])son[x][s[i]]=++tot;
    x=son[x][s[i]];
  }
  return x;
}
void dfs(int x){
  st[x]=++dfn;
  for(int i=0;i<26;i++)if(son[x][i])dfs(son[x][i]);
  en[x]=dfn;
}
inline void ask0(){
  int x=0;
  for(int i=1;i<=k;i++){
    if(!son[x][s[i]]){la=ra=0;return;}
    x=son[x][s[i]];
  }
  la=st[x],ra=en[x];
}
inline void ask1(){
  int x=0;
  for(int i=k;i;i--){
    if(!son[x][s[i]]){lb=rb=0;return;}
    x=son[x][s[i]];
  }
  lb=st[x],rb=en[x];
}
}A,B;
int l[M],r[M],val[M],tot,T[S];
int ins(int x,int a,int b,int c){
  int y=++tot;val[y]=val[x]+1;
  if(a==b)return y;
  int mid=(a+b)>>1;
  if(c<=mid)l[y]=ins(l[x],a,mid,c),r[y]=r[x];else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c);
  return y;
}
int ask(int x,int a,int b){
  if(!x)return 0;
  if(lb<=a&&b<=rb)return val[x];
  int mid=(a+b)>>1,t=0;
  if(lb<=mid)t=ask(l[x],a,mid);
  if(rb>mid)t+=ask(r[x],mid+1,b);
  return t;
}
int main(){
  scanf("%d",&n);
  for(i=1;i<=n;i++){
    read();
    posa[i]=A.ins0();
    posb[i]=B.ins1();
  }
  A.dfs(0),B.dfs(0);
  for(i=1;i<=n;i++)add(A.st[posa[i]],B.st[posb[i]]);
  for(i=1;i<=A.dfn;i++)for(T[i]=T[i-1],j=g[i];j;j=nxt[j])T[i]=ins(T[i],1,B.dfn,v[j]);
  scanf("%d",&m);
  while(m--){
    read(),A.ask0();
    read(),B.ask1();
    if(la&&lb)ans=ask(T[ra],1,B.dfn)-ask(T[la-1],1,B.dfn);else ans=0;
    printf("%d\n",ans);
  }
  return 0;
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值