zoukankan      html  css  js  c++  java
  • 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
    ",sam.solve(pos2[pos[y]],y-x+1));
    132     }
    133     return 0;
    134 }
  • 相关阅读:
    《OOAD与UML那点儿事》目录索引
    《BI那点儿事—数据的艺术》目录索引
    《BI项目笔记》——微软BI项目笔记连载
    VC++常用数据类型转化
    模式识别—最邻近模板匹配法
    C#引用C++开发的DLL
    图像预处理第9步:存为.bmp文件
    图像预处理第8步:紧缩重排数字字符
    图像预处理第7步:标准归一化
    图像预处理第5步:倾斜度调整
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5362675.html
Copyright © 2011-2022 走看看