山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

51nod 小Z的trie(Trie+广义SAM)

 

【题目链接】

 

    http://www.51nod.com/contest/problem.html#!problemId=1647

 

【题意】

 

    给定一个n个字符串的Trie,每次询问一个字符串在Trie上的出现次数。

 

【思路】

 

    将n个字符串构造一个Trie,构造广义后缀自动机,识别Trie中的所有子串。

    则问题转化为求子串[l,r]在所属字符串中的出现次数,和 这道题 类似,采用树上倍增得到|right|的方法。

  比较恶心的是定位字符串的位置=-=。

 

【代码】

 

  1 #include<set>
  2 #include<cmath>
  3 #include<queue>
  4 #include<vector>
  5 #include<cstdio>
  6 #include<cstring>
  7 #include<iostream>
  8 #include<algorithm>
  9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 11 #define rep(a,b,c) for(int a=(b);a>=(c);a--)
 12 using namespace std;
 13 
 14 typedef long long ll;
 15 const int N = 1e6+10;
 16 const int D = 21; 
 17 const int maxnode = 1800010; 
 18 
 19 int pos[N],pos2[N],cur;
 20 
 21 ll read() {
 22     char c=getchar();
 23     ll f=1,x=0;
 24     while(!isdigit(c)) {
 25         if(c=='-') f=-1; c=getchar();
 26     }
 27     while(isdigit(c))
 28         x=x*10+c-'0',c=getchar();
 29     return x*f;
 30 }
 31 
 32 struct SAM
 33 {
 34     int sz,fa[maxnode],mx,ch[maxnode][26],l[maxnode];
 35     int siz[maxnode],b[maxnode],c[N],fat[maxnode][D];
 36     SAM() {
 37         sz=1;
 38         memset(l,0,sizeof(l));
 39         memset(siz,0,sizeof(siz));
 40     }
 41     int add(int c,int p) {
 42         int np=++sz; l[np]=l[p]+1; 
 43         mx=max(mx,l[np]); siz[np]=1;
 44         for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
 45         if(!p) fa[np]=1;
 46         else {
 47             int q=ch[p][c];
 48             if(l[q]==l[p]+1) fa[np]=q;
 49             else {
 50                 int nq=++sz; l[nq]=l[p]+1;
 51                 memcpy(ch[nq],ch[q],sizeof(ch[q]));
 52                 fa[nq]=fa[q];
 53                 fa[np]=fa[q]=nq;
 54                 for(;q==ch[p][c];p=fa[p]) ch[p][c]=nq;
 55             }
 56         }
 57         return np;
 58     }
 59     void get_pre() {
 60         FOR(i,1,sz) c[l[i]]++;
 61         FOR(i,1,mx) c[i]+=c[i-1];
 62         FOR(i,1,sz) b[c[l[i]]--]=i;
 63         rep(i,sz,1) siz[fa[b[i]]]+=siz[b[i]];
 64         FOR(j,1,sz) {
 65             int i=b[j];                                //按照拓扑序递推fat 
 66             fat[i][0]=fa[i];
 67             FOR(j,1,D-1)
 68                 fat[i][j]=fat[fat[i][j-1]][j-1];
 69         }
 70     }
 71     int solve(int u,int len) {
 72         rep(i,D-1,0)
 73             if(l[fat[u][i]]>=len) u=fat[u][i];
 74         return siz[u];
 75     }
 76 } sam;
 77 
 78 struct Node {
 79     int id,np;
 80 };
 81 struct Trie 
 82 {
 83     int sz,ch[N][26];
 84     queue<Node> q;
 85     Trie() {
 86         sz=0;
 87         memset(ch,0,sizeof(ch));
 88     }
 89     void insert(char* s) {
 90         int u=0;
 91         for(int i=0;s[i];i++) {
 92             int c=s[i]-'a';
 93             if(!ch[u][c]) ch[u][c]=++sz;
 94             u=ch[u][c]; pos[++cur]=u;
 95         }
 96     }
 97     void bfs() {
 98         int u=0;
 99         q.push((Node){u,1});
100         while(!q.empty()) {
101             Node qr=q.front(); q.pop();
102             int u=qr.id,p=qr.np;
103             FOR(c,0,25) if(ch[u][c]) {
104                 int v=ch[u][c];
105                 int np=sam.add(c,p);
106                 pos2[v]=np;
107                 q.push((Node){v,np});
108             }
109         }
110     }
111 } trie;
112 
113 int n,m,len[N];
114 char s[N];
115 
116 int main()
117 {
118     n=read();
119     FOR(i,1,n) {
120         scanf("%s",s);
121         len[i]=len[i-1]+strlen(s);
122         trie.insert(s);
123     }
124     trie.bfs();
125     sam.get_pre();
126     scanf("%d",&m);
127     int p,x,y;
128     while(m--) {
129         p=read(),x=read(),y=read();
130         x+=len[p-1],y+=len[p-1];
131         printf("%d\n",sam.solve(pos2[pos[y]],y-x+1));
132     }
133     return 0;
134 }

 

posted on 2016-04-07 11:06  hahalidaxin  阅读(890)  评论(0编辑  收藏  举报