• 后缀自动机


    膜拜clj

    今天重新看了一下后缀自动机的,感受颇深。

    先贴个模板:
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
     
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b)  for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
      {
            int res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    inline LL gll()
      {
          LL res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    
    const int maxN=2*10000;
    
    int N;
    char s[maxN+1000];
    
    struct SAM
      {
          struct node
            {
                int ch[26],fail,maxlen,minlen,size;
                    /*
                    maxlen:能接受的最长字符串长度
                    minlen:能接受的最短字符串长度,为fail的maxlen+1 
                    maxlen-minlen+1:能接受的不同字符串种数
                    size:表示这个状态出现了几次,状态能够表示的所有字符串均出现过size次 
                    fail-tree恰好是字符串逆序的后缀树
                    ch构成一个有向无环图 
                    */
                inline void clear(){mmst(ch,0);fail=maxlen=minlen=size=0;}
            };
            node sn[maxN*2+1000];//空间要乘2
            int idx,last;
            inline void clear(){idx=last=1;sn[idx].clear();}
            inline int newnode(){sn[++idx].clear();return idx;}
            inline void add(int c)
              {
                  int end=newnode();
                  int p=last;
                  last=end;//注意这句话 
                  sn[end].maxlen=sn[p].maxlen+1;
                  for(;p && !sn[p].ch[c];p=sn[p].fail)sn[p].ch[c]=end;//这里生成了新的子串 
                  if(!p)sn[end].fail=1;//注意root是1
                    else
                      { 
                      int q=sn[p].ch[c];
                      if(sn[p].maxlen+1==sn[q].maxlen)sn[end].fail=q;
                      else
                        {
                                  int nq=newnode();
                                    sn[nq]=sn[q];
                                    sn[nq].maxlen=sn[p].maxlen+1;
                                    sn[q].fail=sn[end].fail=nq;
                                    for(;p && sn[p].ch[c]==q;p=sn[p].fail)sn[p].ch[c]=nq;
                        }
                    }
                  sn[end].minlen=sn[sn[end].fail].maxlen+1;
                  /*
                    for(int p=end;p!=1;p=sn[p].fail)sn[p].size++;
                    这样写为暴力修改size,遇到连续个相同字符的数据就会超时
                    可以用LCT优化,具体见bzoj2555
                    */
              }
            int cnt[maxN+100],b[2*maxN+100];
            inline void insert(char *s,int N)
              {
                  int i,p;
                  clear();
                  re(i,1,N)add(s[i]-'a');
                  re(i,1,N)cnt[i]=0;
                re(i,1,idx)cnt[sn[i].maxlen]++;
                re(i,1,N)cnt[i]+=cnt[i-1];
                re(i,1,idx)b[cnt[sn[i].maxlen]--]=i;
                  p=1;re(i,1,N){p=sn[p].ch[s[i]-'a'];sn[p].size++;}
                  red(i,N,1){p=b[i];if(sn[p].fail!=1)sn[sn[p].fail].size+=sn[p].size;}    
              }
        };
    View Code
     
    poj1509
    【题意】
    求一个字符串的最小表示。
    【解析】
    虽然这道题有更简单的做法。。。。。。
    先将这个字符串复制一遍,然后做SAM。然后从根结点开始,不断找最小的儿子走,直到长度为N为止。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
     
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b)  for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
      {
            int res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    inline LL gll()
      {
          LL res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    
    const int maxN=2*10000;
    
    int N;
    char s[maxN+1000];
    
    struct SAM
      {
          struct node
            {
                int ch[26],fail,len;
                inline void clear(){mmst(ch,0);fail=len=0;}
            };
            node sn[maxN*2+1000];//空间要乘2
            int idx,last;
            inline void clear(){idx=last=1;sn[idx].clear();}
            inline int newnode(){sn[++idx].clear();return idx;}
            inline void add(int c)
              {
                  int end=newnode();
                  int p=last;
                  last=end;//注意这句话 
                  sn[end].len=sn[p].len+1;
                  for(;p && !sn[p].ch[c];p=sn[p].fail)sn[p].ch[c]=end;
                  if(!p){sn[end].fail=1;return;}//注意root是1 
                  int q=sn[p].ch[c];
                  if(sn[p].len+1==sn[q].len){sn[end].fail=q;return;}
                  int nq=newnode();
                  sn[nq]=sn[q];
                  sn[nq].len=sn[p].len+1;
                  sn[q].fail=sn[end].fail=nq;
                  for(;p && sn[p].ch[c]==q;p=sn[p].fail)sn[p].ch[c]=nq;
              }
            inline void insert(char *s,int N)
              {
                  int i;
                  clear();
                  re(i,1,N)add(s[i]-'a');
              }
        };
    
    SAM sam;
    
    int main()
      {
          freopen("poj1509.in","r",stdin);
          freopen("poj1509.out","w",stdout);
          int i,j;
          for(int Case=gint();Case;Case--)
            {
                scanf("%s
    ",s+1);
                N=strlen(s+1);
                re(i,1,N)s[N+i]=s[i];
                sam.insert(s,2*N);
                int p=1;
                re(i,1,N)re(j,0,26-1)
                      if(sam.sn[p].ch[j]){p=sam.sn[p].ch[j];break;}
                printf("%d
    ",sam.sn[p].len-N+1);
            }
          return 0;
      }
    View Code
    spoj1811
    【题意】
    求两个字符串的最长公共子串。
    【解析】
    对第一个字符串跑SAM。然后第二个字符串找SAM里跑,如果没有对应的儿子就找fail,类似于KMP,注意对len的理解。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
     
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b)  for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
      {
            int res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    inline LL gll()
      {
          LL res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    
    const int maxN=250000;
    
    struct SAM
      {
          struct node
            {
                int ch[26],fail,maxlen;
                inline void clear(){mmst(ch,0);fail=maxlen=0;}
            };
          node sn[2*maxN+1000];
          int idx,last;
          inline void clear(){sn[idx=last=1].clear();}
          inline int newnode(){sn[++idx].clear();return idx;}
          inline void add(int c)
            {
                int end=newnode();
                int p=last;
                last=end;
                sn[end].maxlen=sn[p].maxlen+1;
                for(;p && !sn[p].ch[c];p=sn[p].fail)sn[p].ch[c]=end;
                if(!p){sn[end].fail=1;return;}
                int q=sn[p].ch[c];
                if(sn[p].maxlen+1==sn[q].maxlen){sn[end].fail=q;return;}
                int nq=newnode();
                sn[nq]=sn[q];
                sn[nq].maxlen=sn[p].maxlen+1;
                sn[q].fail=sn[end].fail=nq;
                for(;p && sn[p].ch[c]==q;p=sn[p].fail)sn[p].ch[c]=nq;
            }
          inline void insert(char *s,int N)
            {
                int i;
                clear();
                re(i,1,N)add(s[i]-'a');
            }
      };
    
    int lena,lenb;
    char a[maxN+100],b[maxN+100];
    SAM sam;
    int ans;
    
    int main()
      {
          freopen("spoj1811.in","r",stdin);
          freopen("spoj1811.out","w",stdout);
          int i;
          scanf("%s
    ",a+1);lena=strlen(a+1);
          scanf("%s
    ",b+1);lenb=strlen(b+1);
          sam.insert(a,lena);
          ans=0;
          int clen=0,p=1;
          re(i,1,lenb)
            {
                int c=b[i]-'a';
                if(sam.sn[p].ch[c])
                  {
                      p=sam.sn[p].ch[c];
                      clen++;
                  }
                else
                  {
                      while(p!=1 && !sam.sn[p].ch[c])p=sam.sn[p].fail;
                      if(!sam.sn[p].ch[c])
                        clen=0;
                      else
                        {
                            clen=sam.sn[p].maxlen+1;
                            p=sam.sn[p].ch[c];
                        }
                        }
                upmax(ans,clen);
            }
          cout<<ans<<endl;
      }
    View Code
    spoj1812
    【题意】
    求多个字符串的最长公共子串
    【解析】
    首先对第一个串做SAM。我们想知道对于SAM的每个节点,和剩下的每个字符串的最长公共子串是多少,然后所有的子串取一个最小值。
    上题类似的做法,不过要更新fail树的祖先的答案,可以最后在延迟更新。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
     
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b)  for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
      {
            int res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    inline LL gll()
      {
          LL res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    
    const int maxT=10;
    const int maxN=100000;
    
    struct SAM
      {
          struct Tnode
            {
                int ch[26],fail,l,nl,ml;
                inline void clear(){mmst(ch,0);fail=l=nl=ml=0;}
            }sn[2*maxN+1000];
          int idx,last;
          inline void clear(){sn[idx=last=1].clear();}
          inline int newnode(){sn[++idx].clear();return idx;}
          inline void add(int z)
            {
                int end=newnode();
                int p=last;
                last=end;
                sn[end].l=sn[p].l+1;
                for(;p && !sn[p].ch[z];p=sn[p].fail)sn[p].ch[z]=end;
                if(!p)sn[end].fail=1;
                else
                  {
                      int q=sn[p].ch[z];
                      if(sn[p].l+1==sn[q].l) sn[end].fail=q;
                      else
                        {
                            int nq=newnode();
                            sn[nq]=sn[q];
                            sn[q].fail=sn[end].fail=nq;
                            sn[nq].l=sn[p].l+1;
                            for(;p && sn[p].ch[z]==q;p=sn[p].fail)sn[p].ch[z]=nq;
                        }
                  }
            }
          int cnt[maxN+100],b[2*maxN+100];
          inline void insert(char *s)
            {
                int i,N=strlen(s+1);
                clear();
                re(i,1,N)add(s[i]-'a');
                re(i,1,N)cnt[i]=0;
                re(i,1,idx)cnt[sn[i].l]++;
                re(i,1,N)cnt[i]+=cnt[i-1];
                re(i,1,idx)b[cnt[sn[i].l]--]=i;
            }
          };
    
    int T;
    char s[maxT+3][maxN+1000];
    SAM sam;
    
    int main()
      {
          freopen("spoj1812.in","r",stdin);
          freopen("spoj1812.out","w",stdout);
          int i,j;
          while(scanf("%s
    ",s[++T]+1)!=EOF);T--;
            sam.insert(s[1]);
            re(i,2,sam.idx)sam.sn[i].ml=sam.sn[i].l;
          re(i,2,T)
            {
                int N=strlen(s[i]+1),p=1,len=0;
                re(j,1,N)
                  {
                      int z=s[i][j]-'a';
                      while(p!=1 && !sam.sn[p].ch[z]){p=sam.sn[p].fail;len=sam.sn[p].l;}
                      if(sam.sn[p].ch[z]){len++;p=sam.sn[p].ch[z];}
                      upmax(sam.sn[p].nl,len);
                  }
                red(j,sam.idx,2)
                  {
                      int p=sam.b[j];
                      upmin(sam.sn[p].ml,sam.sn[p].nl);
                      if(sam.sn[p].fail!=1) upmax(sam.sn[sam.sn[p].fail].nl,sam.sn[p].nl);
                      sam.sn[p].nl=0;
                  }
            }
          int ans=0;
          re(i,1,sam.idx)upmax(ans,sam.sn[i].ml);
          cout<<ans<<endl;
          return 0;
      }
    View Code
    hdu4641
    【题意】
    给定一个原始的字符串,有m次操作,每次操作可以向该字符串末尾添加一个字符或者询问在字符串中出现了至少K次的子串一共有多少个。
    【解析】
    就是在模板中求size值大于等于K的个数。这里有个要点,如果大于K就不必再询问祖先了。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
    
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b) for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
    {
    int res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    inline LL gll()
    {
    LL res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    
    const int maxN=50000+200000;
    const int maxM=200000;
    const int maxK=50000;
    
    int N,K,M;
    LL ans;
    
    struct SAM
    {
    struct Tnode
    {
    int ch[26],fail,l,right;
    inline void clear(){mmst(ch,0);fail=l=right=0;}
    }node[2*maxN+1000];
    int idx,last;
    inline void clear(){node[idx=last=1].clear();}
    inline int newnode(){node[++idx].clear();return idx;}
    inline void add(int z)
    {
    int end=newnode();
    int p=last;
    last=end;
    node[end].l=node[p].l+1;
    for(;p && !node[p].ch[z];p=node[p].fail)node[p].ch[z]=end;
    if(!p)node[end].fail=1;
    else
    {
    int q=node[p].ch[z];
    if(node[p].l+1==node[q].l)node[end].fail=q;
    else
    {
    int nq=newnode();
    node[nq]=node[q];
    node[q].fail=node[end].fail=nq;
    node[nq].l=node[p].l+1;
    for(;p && node[p].ch[z]==q;p=node[p].fail)node[p].ch[z]=nq;
    }
    }
    for(p=end;p!=1;p=node[p].fail)
    {
    node[p].right++;
    if(node[p].right>K)break;
    if(node[p].right==K)
    {
    int ge=node[p].l-node[node[p].fail].l;
    ans+=LL(ge);
    }
    }
    }
    };
    
    SAM sam;
    
    
    int main()
    {
    freopen("hdu4641.in","r",stdin);
    freopen("hdu4641.out","w",stdout);
    int i;
    while(scanf("%d%d%d
    ",&N,&M,&K)!=EOF)
    {
    sam.clear();
    ans=0;
    re(i,1,N)
    {
    char z=getchar();
    sam.add(z-'a');
    }
    while(M--)
    {
    int flag=gint();
    if(flag==2)
    printf("%I64d
    ",ans);
    else
    {
    char z=getchar();
    sam.add(z-'a');
    }
    }
    }
    return 0;
    }
    View Code
    spoj7258
    【题意】
    求去重后的第K大子串。
    【解析】
    SAM是一个有向无环图。
    考虑诸位确定答案。
    假设我们知道下步分别取a,b,c,......,z的方案数,我们就可以从a到z枚举,如果方案数小于K那么,K减去方案数,否则下一位就选这个字母。
    方案数可以用拓扑序确定。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
    
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b) for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
    {
    int res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    inline LL gll()
    {
    LL res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    
    const int maxN=90000;
    
    struct SAM
    {
    struct Tnode
    {
    int ch[26],fail,l;
    LL cnt;
    inline void clear(){mmst(ch,0);fail=l=0;cnt=0;}
    }sn[2*maxN+100];
    int idx,last;
    inline void clear(){sn[idx=last=1].clear();}
    inline int newnode(){sn[++idx].clear();return idx;}
    inline void add(int z)
    {
    int end=newnode();
    int p=last;
    last=end;
    sn[end].l=sn[p].l+1;
    for(;p && !sn[p].ch[z];p=sn[p].fail)sn[p].ch[z]=end;
    if(!p)sn[end].fail=1;
    else
    {
    int q=sn[p].ch[z];
    if(sn[p].l+1==sn[q].l)sn[end].fail=q;
    else
    {
    int nq=newnode();
    sn[nq]=sn[q];
    sn[nq].l=sn[p].l+1;
    sn[q].fail=sn[end].fail=nq;
    for(;p && sn[p].ch[z]==q;p=sn[p].fail)sn[p].ch[z]=nq;
    }
    }
    }
    inline void insert(char *s)
    {
    int i,N=strlen(s+1);
    clear();
    re(i,1,N)add(s[i]-'a');
    }
    };
    
    SAM sam;
    char s[maxN+100];
    
    int du[2*maxN+100];
    int head,tail,que[2*maxN+100];
    
    int ge,out[maxN+100];
    int main()
    {
    freopen("spoj7258.in","r",stdin);
    freopen("spoj7258.out","w",stdout);
    int i,j;
    scanf("%s
    ",s+1);
    sam.insert(s);
    re(i,1,sam.idx)re(j,0,26-1)if(sam.sn[i].ch[j]) du[sam.sn[i].ch[j]]++;
    head=0;tail=-1;
    re(i,1,sam.idx)if(du[i]==0)que[++tail]=i;
    while(head<=tail)
    {
    int u=que[head++];
    re(j,0,26-1)if(sam.sn[u].ch[j])
    {
    int v=sam.sn[u].ch[j];
    du[v]--;
    if(du[v]==0)que[++tail]=v;
    }
    }
    red(i,tail,0)
    {
    int u=que[i];
    sam.sn[u].cnt=1;
    re(j,0,26-1)if(sam.sn[u].ch[j])
    {
    int v=sam.sn[u].ch[j];
    sam.sn[u].cnt+=sam.sn[v].cnt;
    }
    }
    for(int Q=gint();Q;Q--)
    {
    LL K=gll();
    int u=1;
    ge=0;
    while(K!=0)
    {
    re(i,0,26-1)
    {
    int v=sam.sn[u].ch[i];
    if(sam.sn[v].cnt<K)
    K-=sam.sn[v].cnt;
    else
    {
    out[++ge]=i;
    u=v;
    K--;
    break;
    }
    }
    }
    re(i,1,ge)printf("%c",out[i]+'a');printf("
    ");
    }
    return 0;
    }
    View Code
    hdu4622
    【题意】
    给定一个字符串,长度最长为2000,有至多10000组询问,每个询问给定一个区间,求出该区间内共有多少个不同的子串。
    【解析】
    离线出来。
    先将区间排序,左端点从小到大,左端点相同就右端点从小到大。
    相同的左端点可以归为一组,对每个后缀做SAM,因为最多只有2000个后缀,不超时。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
    
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b) for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
    {
    int res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    inline LL gll()
    {
    LL res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    
    const int maxN=2000;
    const int maxQ=10000;
    
    int N;
    char s[maxN+100];
    int Q;
    struct Tdata
    {
    int l,r,id;
    LL ans;
    }data[maxQ+100];
    
    inline bool cmp(Tdata a,Tdata b){return (a.l==b.l)?a.r<b.r:a.l<b.l;}
    inline bool cmpid(Tdata a,Tdata b){return a.id<b.id;}
    
    struct SAM
    {
    struct Tnode
    {
    int ch[26],fail,l;
    inline void clear(){mmst(ch,0);fail=l=0;}
    }sn[2*maxN+100];
    int idx,last;
    LL cnt;
    inline void clear(){cnt=0;sn[idx=last=1].clear();}
    inline int newnode(){sn[++idx].clear();return idx;}
    inline void add(int z)
    {
    int end=newnode();
    int p=last;
    last=end;
    sn[end].l=sn[p].l+1;
    for(;p && !sn[p].ch[z];p=sn[p].fail)
    {
    sn[p].ch[z]=end;
    if(p!=1) cnt+=LL(sn[p].l-sn[sn[p].fail].l); else cnt++;
    }
    if(!p) sn[end].fail=1;
    else
    {
    int q=sn[p].ch[z];
    if(sn[p].l+1==sn[q].l) sn[end].fail=q;
    else
    {
    int nq=newnode();
    sn[nq]=sn[q];
    sn[nq].l=sn[p].l+1;
    sn[q].fail=sn[end].fail=nq;
    for(;p && sn[p].ch[z]==q;p=sn[p].fail)sn[p].ch[z]=nq;
    }
    }
    }
    };
    
    SAM sam;
    
    int main()
    {
    freopen("hdu4622.in","r",stdin);
    freopen("hdu4622.out","w",stdout);
    int i,j;
    for(int Case=gint();Case;Case--)
    {
    scanf("%s
    ",s+1);
    Q=gint();
    re(i,1,Q)data[i].l=gint(),data[i].r=gint(),data[i].id=i;
    sort(data+1,data+Q+1,cmp);
    int r;
    re(i,1,Q)
    {
    if(data[i].l!=data[i-1].l){sam.clear();r=data[i].l-1;}
    re(j,r+1,data[i].r)sam.add(s[j]-'a');
    r=data[i].r;
    data[i].ans=sam.cnt;
    }
    sort(data+1,data+Q+1,cmpid);
    re(i,1,Q)printf("%I64d
    ",data[i].ans);
    }
    return 0;
    }
    View Code
    bzoj3879
    【题意】
    给一个字符串。有多个询问,每个询问有若干个后缀,问这些后缀的最长公共前缀。
    【解析】
    网上的解法是后缀树,在后缀树中求LCA。然后根据性质我们可以通过SAM构造出后缀树,这样可以避免普通后缀树构造算法的冗长。
    但是我看到这道题就想到了后缀数组,可以利用求heigh时的单调性,用单调栈。
    速度比后缀树快。。。
    乱入了一个后缀数组代码。。。。。。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
    
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b) for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
    {
    int res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    inline LL gll()
    {
    LL res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    
    const int maxN=500000;
    const LL Mod=23333333333333333LL;
    const int maxT=3000000;
    
    int N,M;
    char s[maxN+1000];
    
    int sa[maxN+100],rank[maxN+100],height[maxN+100];
    int wa[maxN+100],wb[maxN+100],table[maxN+100];
    inline bool cmp(int *y,int a,int b,int len){return y[a]==y[b] && y[a+len]==y[b+len];}
    inline void da()
    {
    int i,j,k,p,tol,*x=wa,*y=wb;
    p=0;re(i,1,N)upmax(p,x[i]=s[i]);
    re(i,1,p)table[i]=0;
    re(i,1,N)table[x[i]]++;
    re(i,1,p)table[i]+=table[i-1];
    red(i,N,1)sa[table[x[i]]--]=i;
    for(swap(x,y),p=x[sa[1]]=1,i=2;i<=N;i++)x[sa[i]]=cmp(y,sa[i],sa[i-1],0)?p:++p;
    for(j=1;p<N;j<<=1)
    {
    tol=0;re(i,N-j+1,N)y[++tol]=i;
    re(i,1,N)if(sa[i]-j>=1)y[++tol]=sa[i]-j;
    re(i,1,p)table[i]=0;
    re(i,1,N)table[x[y[i]]]++;
    re(i,1,p)table[i]+=table[i-1];
    red(i,N,1)sa[table[x[y[i]]]--]=y[i];
    for(swap(x,y),p=x[sa[1]]=1,i=2;i<=N;i++)x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p:++p;
    }
    re(i,1,N)rank[sa[i]]=i;
    for(i=1,k=0;i<=N-1;height[rank[i++]]=k)
    for(k=max(0,k-1),j=sa[rank[i]-1];s[i+k]==s[j+k];k++);
    }
    
    int lg2[maxN+100];
    int RMQ[31][maxN+100];
    
    inline int ask(int l,int r)
    {
    int h=lg2[r-l+1];
    return min(RMQ[h][l],RMQ[h][r-two(h)+1]);
    }
    
    int t;
    int p[maxT+100];////注意范围 不是maxN 
    
    int top;
    LL val[maxN+100],cnt[maxN+100];
    
    inline LL solve()
    {
    LL res=0,sum=0;int i;
    top=0;
    re(i,2,t)
    {
    int v=ask(p[i-1]+1,p[i]);
    top++;
    val[top]=LL(v);
    cnt[top]=1;
    sum=(sum+LL(v))%Mod;
    while(top>=2 && val[top-1]>=val[top])
    {
    sum=(sum-cnt[top-1]*(val[top-1]-val[top])%Mod)%Mod;
    val[top-1]=val[top];
    cnt[top-1]+=cnt[top];
    top--;
    }
    res=(res+sum)%Mod;
    }
    res=(res%Mod+Mod)%Mod;
    return res;
    }
    
    int main()
    {
    freopen("bzoj3879.in","r",stdin);
    freopen("bzoj3879.out","w",stdout);
    int i,j;
    N=gint();M=gint();
    scanf("%s
    ",s+1);
    s[++N]=' ';
    da();
    lg2[1]=0;re(i,2,N)lg2[i]=lg2[i>>1]+1;
    re(i,1,N)RMQ[0][i]=height[i];
    re(j,1,30)re(i,1,N)if(i+two(j-1)<=N) RMQ[j][i]=min(RMQ[j-1][i],RMQ[j-1][i+two(j-1)]); else RMQ[j][i]=RMQ[j-1][i];
    re(i,1,M)
    {
    t=gint();
    re(j,1,t)p[j]=gint();
    re(j,1,t)p[j]=rank[p[j]];
    sort(p+1,p+t+1);
    t=unique(p+1,p+t+1)-p-1;
    cout<<solve()<<endl;
    }
    return 0;
    }
    View Code
    spoj8222
    【题意】
    给定一个字符串,求出现次数最多的长度为 i 的子串的次数,i 的取值为 1 - len,len表示这个字符串的长度。
    【解析】
    表示刚开始以为是水题,然后直接用线段树。结果被spoj卡了,TLE。
    膜拜cjl,详情见cjl论文。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
    
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b) for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
    {
    int res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    inline LL gll()
    {
    LL res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    
    const int maxN=250000;
    
    struct SAM
    {
    struct Tnode
    {
    int ch[26],fail,l,size;
    inline void clear(){mmst(ch,0);fail=l=size=0;}
    }sn[2*maxN+100];
    int idx,last;
    inline void clear(){sn[idx=last=1].clear();}
    inline int newnode(){sn[++idx].clear();return idx;}
    inline void add(int z)
    {
    int end=newnode();
    int p=last;
    last=end;
    sn[end].l=sn[p].l+1;
    for(;p && !sn[p].ch[z];p=sn[p].fail)sn[p].ch[z]=end;
    if(!p) sn[end].fail=1;
    else
    {
    int q=sn[p].ch[z];
    if(sn[p].l+1==sn[q].l) sn[end].fail=q;
    else
    {
    int nq=newnode();
    sn[nq]=sn[q];
    sn[q].fail=sn[end].fail=nq;
    sn[nq].l=sn[p].l+1;
    for(;p && sn[p].ch[z]==q;p=sn[p].fail)sn[p].ch[z]=nq;
    }
    }
    //for(p=end;p;p=sn[p].fail)sn[p].size++;
    }
    int du[2*maxN+100],head,tail,que[2*maxN+100];
    inline void insert(char *s,int N)
    {
    int i;
    clear();
    re(i,1,N)add(s[i]-'a');
    int p=1;
    re(i,1,N){p=sn[p].ch[s[i]-'a'];sn[p].size++;}
    re(i,1,idx)du[i]=0;
    re(i,2,idx)du[sn[i].fail]++;
    head=0;tail=-1;
    re(i,1,idx)if(du[i]==0)que[++tail]=i;
    while(head<=tail)
    {
    int u=que[head++],fa=sn[u].fail;
    if(fa!=1)
    {
    sn[fa].size+=sn[u].size;
    du[fa]--;
    if(du[fa]==0) que[++tail]=fa;
    }
    }
    }
    };
    
    SAM sam;
    
    int N;
    char s[maxN+100];
    
    int F[maxN+100];
    
    int main()
    {
    freopen("spoj8222.in","r",stdin);
    freopen("spoj8222.out","w",stdout);
    int i;
    scanf("%s
    ",s+1);N=strlen(s+1);
    sam.insert(s,N);
    re(i,2,sam.idx)upmax(F[sam.sn[i].l],sam.sn[i].size);
    red(i,N-1,1)upmax(F[i],F[i+1]);
    re(i,1,N)printf("%d
    ",F[i]);
    return 0;
    }
    View Code


    bzoj2555
    【题意】
    给定一个原始的字符串,有若干次操作,每次操作可以向该字符串末尾添加一个字符串或者询问某个子串在字符串中出现的次数。强制在线。
    【解析】
    我们求size的时候是沿祖先向上不断+1的。
    这样很慢。
    可以用LCT维护。
    第一次写,代码比较冗长。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
    
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b) for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
    {
    int res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    inline LL gll()
    {
    LL res=0;bool neg=0;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){neg=1;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return (neg)?-res:res; 
    }
    
    const int maxN=600000;
    
    struct SAM
    {
    struct Splay_Node
    {
    Splay_Node *son[2],*fa,*path_parent;
    int isRev,val,add;
    inline Splay_Node(){son[0]=son[1]=fa=path_parent=0;isRev=val=add=0;}
    inline void down()
    {
    if(isRev)
    {
    swap(son[0],son[1]);
    if(son[0])son[0]->isRev^=1;
    if(son[1])son[1]->isRev^=1;
    isRev=0;
    }
    if(add!=0)
    {
    if(son[0])son[0]->add+=add,son[0]->val+=add;
    if(son[1])son[1]->add+=add,son[1]->val+=add;
    add=0;
    }
    }
    };
    Splay_Node *root;
    inline void Splay_Rotate(Splay_Node *x,int flag)
    {
    Splay_Node *y=x->fa,*z=y->fa;
    x->path_parent=y->path_parent;y->path_parent=0;
    if(x->son[flag])x->son[flag]->fa=y;y->son[flag^1]=x->son[flag];
    x->son[flag]=y;y->fa=x;
    x->fa=z;if(z)z->son[y==z->son[1]]=x;
    }
    inline void Splay(Splay_Node *x)
    {
    Splay_Node *y,*z;
    while(x->fa)
    {
    y=x->fa;z=y->fa;
    if(z)z->down();if(y)y->down();if(x)x->down();
    if(!z){Splay_Rotate(x,x==y->son[0]);break;}
    int L=(x==y->son[0]),R=(y==z->son[0]);
    if(L==R){Splay_Rotate(y,L);Splay_Rotate(x,R);continue;}
    if(L!=R){Splay_Rotate(x,L);Splay_Rotate(x,R);continue;}
    }
    x->down();
    }
    inline void LCT_Access(Splay_Node *x)
    {
    Splay_Node *y;
    for(y=0;x;y=x,x=x->path_parent)
    {
    Splay(x);
    x->down();
    if(x->son[1]){x->son[1]->fa=0;x->son[1]->path_parent=x;}
    x->son[1]=y;
    if(y){y->fa=x;y->path_parent=0;}
    }
    }
    inline void LCT_Evert(Splay_Node *x)
    {
    LCT_Access(x);
    Splay(x);
    x->isRev^=1;
    x->down();
    }
    inline void LCT_Link(Splay_Node *u,Splay_Node *v)
    {
    LCT_Evert(u);
    Splay(u);
    u->path_parent=v;
    }
    inline void LCT_Cut(Splay_Node *u,Splay_Node *v)
    {
    LCT_Evert(root);
    LCT_Access(u);
    LCT_Access(v);
    Splay(u);
    u->path_parent=0;
    }
    inline void LCT_Add(Splay_Node *u)
    {
    LCT_Evert(root);
    LCT_Access(u);
    Splay(u);
    u->val++;u->add++;
    u->down();
    }
    inline int LCT_Ask(Splay_Node *u)
    {
    Splay(u);
    return u->val;
    }
    struct Tnode
    {
    int ch[26],fail,l;Splay_Node *pos;
    inline void clear(){mmst(ch,0);fail=l=0;pos=new Splay_Node;}
    }sn[2*maxN+100];
    int idx,last;
    inline void clear(){sn[idx=last=1].clear();root=sn[1].pos;}
    inline int newnode(){sn[++idx].clear();return idx;}
    inline void add(int z)
    {
    int end=newnode();
    int p=last;
    last=end;
    sn[end].l=sn[p].l+1;
    for(;p && !sn[p].ch[z];p=sn[p].fail)sn[p].ch[z]=end;
    if(!p)
    {
    sn[end].fail=1;
    LCT_Link(sn[end].pos,sn[sn[end].fail].pos);
    }
    else
    {
    int q=sn[p].ch[z];
    if(sn[p].l+1==sn[q].l)
    {
    sn[end].fail=q;
    LCT_Link(sn[end].pos,sn[sn[end].fail].pos);
    }
    else
    {
    int nq=newnode();
    Splay_Node *temp=sn[nq].pos;
    sn[nq]=sn[q];
    sn[nq].pos=temp;
    sn[nq].pos->val=LCT_Ask(sn[q].pos);//注意,常错写成 sn[nq].pos->val=sn[q].pos->val
    sn[nq].l=sn[p].l+1;
    //注意不要把pos全部复制过来,但是pos的val要复制
    LCT_Cut(sn[q].pos,sn[sn[q].fail].pos);
    sn[q].fail=sn[end].fail=nq;
    LCT_Link(sn[q].pos,sn[sn[q].fail].pos);
    LCT_Link(sn[end].pos,sn[sn[end].fail].pos);
    LCT_Link(sn[nq].pos,sn[sn[nq].fail].pos);
    for(;p && sn[p].ch[z]==q;p=sn[p].fail)sn[p].ch[z]=nq;
    }
    }
    LCT_Add(sn[end].pos);
    }
    };
    
    SAM sam;
    
    const int maxQL=3000000;
    char s[maxQL+1000];
    
    inline void decodewithmark(char *s,int mark)
    {
    int i;
    re(i,0,strlen(s+1)-1)
    {
    mark=(mark*131+i)%strlen(s+1);
    swap(s[i+1],s[mark+1]);
    }
    }
    
    int main()
    {
    freopen("bzoj2555.in","r",stdin);
    freopen("bzoj2555.out","w",stdout);
    int Q=gint(),i,mark=0;
    sam.clear();
    scanf("%s
    ",s+1);
    re(i,1,strlen(s+1))sam.add(s[i]-'A');
    for(;Q;Q--)
    {
    char type[20];
    scanf("%s%s
    ",type+1,s+1);
    decodewithmark(s,mark);
    if(type[1]=='A')
    re(i,1,strlen(s+1))sam.add(s[i]-'A');
    else
    {
    int p=1,len,res=-1;
    re(i,1,strlen(s+1))
    {
    int z=s[i]-'A';
    if(sam.sn[p].ch[z]) p=sam.sn[p].ch[z]; else {res=0;break;}    
    }
    if(res!=0)res=sam.LCT_Ask(sam.sn[p].pos);
    printf("%d
    ",res);
    mark^=res;
    }
    }
    return 0;
    }
    View Code
  • 相关阅读:
    20200924-4 代码规范,结对要求
    20200924-2 功能测试
    20200917-1 每周例行报告
    20200917-3 白名单
    20200917-2 词频统计 已更新附加题!
    20200910-1 每周例行报告
    20200924-2功能测试
    20200924-1每周例行报告
    20200924-3单元测试
    20200924-5 四则运算,结对
  • 原文地址:https://www.cnblogs.com/maijing/p/4649468.html
Copyright © 2020-2023  润新知