HDU5790 Prefix 字典树+主席树

分析:这个题和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;
}
View Code
原文地址:https://www.cnblogs.com/shuguangzw/p/5735890.html