zoukankan      html  css  js  c++  java
  • 2019.4.11 一题 XSY 1551 ——广义后缀数组(trie上后缀数组)

    参考:http://www.mamicode.com/info-detail-1949898.html (log2

       https://blog.csdn.net/geotcbrl/article/details/50907662

       https://blog.csdn.net/cdsszjj/article/details/79920308

       https://blog.csdn.net/ez_yww/article/details/77072632

    trie 上后缀数组想做的是把 trie 树每个节点开始到根的字符串排好序,求出 rk[ ] 和 sa[ ] ,需要的话也可以求出 ht[ ]。

    普通后缀数组比较大小是通过倍增,即 [ i , i+k-1 ] 和 [ i+k , i+2k-1 ] 这两个位置作为两个关键字得到 [ i , i+2k-1 ] 的排名。这里也一样。

    在树上的话, i+k 变成 i 点往上第 k 个祖先;所以先处理好祖先的倍增数组;顺便作出 dep[ ] ;

    希望把每个 2t 时刻的 rk 数组存下来,所以令 rk[ t ][ i ] 表示第 t 次比较的时候 i 的排名。

    当前这次比较的时候,tp[ ] 里要存按第二关键字排好序的序列,即 tp[ i ] 表示 “ 2t-1 次祖先排名为 i 的节点是谁 ” ;这里的 “排名为 i ” 指的是 “向上 2t-1 范围的字符串” 排名,即 rk[ t-1 ][ i ] 。

    所以现在已知上一次的 sa 和 rk ,希望做出 tp[ ] 。只要记录一下每个点的 2t-1 次后代有些谁(注意可能有多个点),然后像平常一样把没有 2t-1 次祖先的点填在最前面,再按 sa 枚举,tp[ ++tot ] = 后代 即可。

    原来用 vector 存了这些后代。但非常慢。每次通过 pre[ i ][ t-1 ] 连一个临接表出来会快很多。

    然后希望作出 ht 。先要作出 ht[ i ][ 0 ] 。

    现在真实的排名是最后一次做出的那个 rk 。所以 ht 是基于最后一次的 rk 和 sa 上求的。保留之前的 rk 可以用来求相邻两个字符串的 LCP 。就是像倍增一样。如果 rk[ t ][ x ] == rk[ t ][ y ] ,说明 i 和 j 向上 2t 个字符都是一样的,那么 ret+= bin[ t ] , x = pre[ x ][ t ] , y = pre[ y ][ t ] 。

    当然也可以不保留这些 rk ,倍增地存一下每个点往上的哈希值也行。(所以比较两个串的复杂度是 log 而不是 log2 的!“二分” 和 “提取哈希值” 可以一起做!)

    (这样有一个做法,就是启发式合并,合并子树的时候把小的部分的字符串二分地插入大的部分的字符串集合中。但支持 “提取某位置的元素” 和 “插入” 的数据结构会带 log ,所以是 log3 ,真遗憾)

    注意桶要包含 0 位置。因为根向上没有字符,初始 rk 是 0 。同时注意输入的边上字符有 0 ,所以把输入都 +1 ,体现 “没有” 比 0 大。

    然后这道题再套一个线段树合并就行了。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<set>
    #define ll long long
    using namespace std;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int Mx(int a,int b){return a>b?a:b;}
    int Mn(int a,int b){return a<b?a:b;}
    const int N=2e5+5,K=18,bs=10007,md=1e9+9;
    int n,dep[N],hs[N][K+5],pre[N][K],lj[N];
    int sa[N],rk[N],ht[N][K+5],bin[K+5],lg[N];
    int hd[N],xnt,to[N],nxt[N],rt[N],ans;
    struct Node{
      int x;
      Node(int x=0):x(x) {}
      bool operator< (const Node &b)const
      {return rk[x]<rk[b.x];}
    };
    set<Node> st[N];
    set<Node>::iterator it,it2;
    int get_lcp(int u,int v)
    {
      int ret=0;
      for(int t=lg[Mn(dep[u],dep[v])];t>=0;t--)//Mn not Mx
        if(pre[u][t]&&pre[v][t]&&hs[u][t]==hs[v][t])//if pre[][]
          u=pre[u][t], v=pre[v][t], ret+=bin[t];
      return ret;
    }
    bool cmp(int u,int v)
    {
      for(int t=lg[Mn(dep[u],dep[v])];t>=0;t--)//Mn
        if(pre[u][t]&&pre[v][t]&&hs[u][t]==hs[v][t])//pre[][]
          u=pre[u][t], v=pre[v][t];
      return hs[u][0]<hs[v][0];
    }
    void get_ht()
    {
      for(int i=2;i<=n;i++)
        ht[i][0]=get_lcp(sa[i-1],sa[i]);
      for(int t=1;t<=lg[n];t++)
        for(int i=1;i+bin[t]-1<=n;i++)
          ht[i][t]=Mn(ht[i][t-1],ht[i+bin[t-1]][t-1]);
    }
    int qry_ht(int u,int v)
    {
      if(u==v)return dep[u];
      u=rk[u]; v=rk[v]; if(u>v)swap(u,v);
      u++; int d=lg[v-u+1];
      return Mn(ht[u][d],ht[v-bin[d]+1][d]);
    }
    int mrg(int &u,int v)
    {
      int ret=0;
      if(st[u].size()<st[v].size())swap(u,v);
      for(it=st[v].begin();it!=st[v].end();it++)
        {
          st[u].insert(*it);
          it2=st[u].find(*it);
          if(it2!=st[u].begin())
        {
          it2--; ret=Mx(ret,qry_ht((*it2).x,(*it).x));
          it2++;
        }
          it2++; if(it2==st[u].end())continue;
          ret=Mx(ret,qry_ht((*it2).x,(*it).x));
        }
      return ret;
    }
    void dfs(int cr)
    {
      rt[cr]=cr; st[rt[cr]].insert(Node(cr));
      int ret=0;
      for(int i=hd[cr],v;i;i=nxt[i])
        {
          dfs(v=to[i]);
          ret=Mx(ret,mrg(rt[cr],rt[v]));
        }
      if(st[rt[cr]].size()>1)//if!!!
        {
          ans=Mx(ans,dep[cr]+ret);
        }
    }
    int main()
    {
      freopen("recollection.in","r",stdin);
      freopen("recollection.out","w",stdout);
      n=rdn();
      bin[0]=1;for(int i=1;i<=K;i++)bin[i]=bin[i-1]<<1;
      for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
      lj[0]=1;for(int i=1;i<=n;i++)lj[i]=(ll)lj[i-1]*bs%md;
      int he=0, tl=0;
      for(int i=2;i<=n;i++)
        {
          pre[i][0]=rdn();hs[i][0]=rdn()+1;//+1 for cmp empty
          to[++xnt]=i; nxt[xnt]=hd[pre[i][0]]; hd[pre[i][0]]=xnt;
        }
      for(int i=2;i<=n;i++)
        {
          dep[i]=dep[pre[i][0]]+1;
          for(int t=1,d=pre[i][0];(d=pre[i][t-1]);t++)
        {
          pre[i][t]=pre[d][t-1];
          hs[i][t]=((ll)hs[i][t-1]*lj[bin[t-1]]+hs[d][t-1])%md;
        }
        }
      for(int i=1;i<=n;i++)sa[i]=i; sort(sa+1,sa+n+1,cmp);
      for(int i=1;i<=n;i++)rk[sa[i]]=i;
      get_ht(); dfs(1);
      printf("%d
    ",ans);
      return 0;
    }
    log^2
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define ls Ls[cr]
    #define rs Rs[cr]
    #define pb push_back
    using namespace std;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int Mx(int a,int b){return a>b?a:b;}
    int Mn(int a,int b){return a<b?a:b;}
    const int N=2e5+5,K=20,M=N*K;
    int n,dep[N],pre[N][K],hd[N],xnt,to[N],nxt[N];
    int ht[K][N],rk[K][N],sa[N],tp[N],tx[N],lm,ans;
    int bin[K],lg[N],rt[N],Ls[M],Rs[M],fr[M],sc[M],sm[M],tot;
    int h2[N],xt2,t2[N],nt2[N];
    void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
    void ad2(int x,int y){t2[++xt2]=y;nt2[xt2]=h2[x];h2[x]=xt2;}
    void Rsort(int n,int nm,int t)
    {
      for(int i=0;i<=nm;i++)tx[i]=0;////// 0 !!!! for empty
      for(int i=1;i<=n;i++)tx[rk[t][i]]++;
      for(int i=1;i<=nm;i++)tx[i]+=tx[i-1];
      for(int i=n;i;i--)sa[tx[rk[t][tp[i]]]--]=tp[i];
    }
    void get_sa(int n,int nm)
    {
      for(int i=1;i<=n;i++)tp[i]=i;
      Rsort(n,nm,0);
      for(int t=1;;t++)
        {
          xt2=0; memset(h2,0,sizeof h2);
          for(int i=1;i<=n;i++)
        if(pre[i][t-1])ad2(pre[i][t-1],i);
          int tot=0;
          for(int i=1;i<=n;i++)
        if(!pre[i][t-1])tp[++tot]=i;
          for(int i=1;i<=n;i++)
        for(int j=h2[sa[i]];j;j=nt2[j])
          tp[++tot]=t2[j];
          Rsort(n,nm,t-1); rk[t][sa[1]]=nm=1;
          for(int i=2;i<=n;i++)
        {
          int cr=sa[i], u=pre[cr][t-1], v=pre[sa[i-1]][t-1];
          rk[t][cr]=(rk[t-1][cr]==rk[t-1][sa[i-1]]&&rk[t-1][u]==rk[t-1][v])?nm:++nm;
        }
          lm=t; if(nm==n)break;
        }
    }
    int get_lcp(int u,int v)
    {
      int ret=0;
      for(int t=lm;t>=0;t--)//t=lm!!
        if(pre[u][t]&&pre[v][t]&&rk[t][u]==rk[t][v])//pre
          u=pre[u][t], v=pre[v][t], ret+=bin[t];
      return ret;
    }
    void get_ht()
    {
      for(int i=2;i<=n;i++)ht[0][i]=get_lcp(sa[i-1],sa[i]);
      for(int t=1;t<=lg[n];t++)
        for(int i=1;i<=n;i++)
          ht[t][i]=Mn(ht[t-1][i],ht[t-1][i+bin[t-1]]);
    }
    int qry_ht(int l,int r)
    {
      if(l==r)return dep[sa[l]];
      if(l>r)swap(l,r); l++; int d=lg[r-l+1];
      int ret=Mn(ht[d][l],ht[d][r-bin[d]+1]);
      return ret;
    }
    void build(int l,int r,int &cr,int p)
    {
      cr=++tot; fr[cr]=sc[cr]=p;
      if(l==r)return; int mid=l+r>>1;
      if(p<=mid)build(l,mid,ls,p);
      else build(mid+1,r,rs,p);
    }
    void mrg(int l,int r,int &cr,int pr)
    {
      if(!cr){cr=pr;return;} if(!pr)return;
      int mid=l+r>>1;
      mrg(l,mid,ls,Ls[pr]); mrg(mid+1,r,rs,Rs[pr]);
      fr[cr]=(ls?fr[ls]:fr[rs]); sc[cr]=(rs?sc[rs]:sc[ls]);
      sm[cr]=Mx(sm[ls],sm[rs]);
      if(fr[ls]&&fr[rs])
        sm[cr]=Mx(sm[cr],qry_ht(sc[ls],fr[rs]));
    }
    void dfs(int cr)
    {
      build(1,n,rt[cr],rk[lm][cr]);
      for(int i=hd[cr],v;i;i=nxt[i])
        {
          dfs(v=to[i]);
          mrg(1,n,rt[cr],rt[v]);
        }
      if(hd[cr])
        {
          ans=Mx(ans,dep[cr]+sm[rt[cr]]);
        }
    }
    int main()
    {
      freopen("recollection.in","r",stdin);
      freopen("recollection.out","w",stdout);
      n=rdn();
      for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
      bin[0]=1;for(int i=1;bin[i-1]<=n;i++)bin[i]=bin[i-1]<<1;
      for(int i=2;i<=n;i++)
        {
          int fa=rdn(); rk[0][i]=rdn()+1;//+1!!!!! for cmp with empty
          dep[i]=dep[fa]+1; pre[i][0]=fa; add(fa,i);
          for(int t=1,d=fa;(d=pre[i][t-1]);t++)
        pre[i][t]=pre[d][t-1];
        }
      get_sa(n,301); get_ht();
      dfs(1);
      printf("%d
    ",ans);
      return 0;
    }
    log
  • 相关阅读:
    泛微云桥e-Bridge 目录遍历,任意文件读取
    (CVE-2020-8209)XenMobile-控制台存在任意文件读取漏洞
    selenium 使用初
    将HTML文件转换为MD文件
    Python对word文档进行操作
    使用java安装jar包出错,提示不是有效的JDK java主目录
    Windows server 2012安装VM tools异常解决办法
    ifconfig 命令,改变主机名,改DNS hosts、关闭selinux firewalld netfilter 、防火墙iptables规则
    iostat iotop 查看硬盘的读写、 free 查看内存的命令 、netstat 命令查看网络、tcpdump 命令
    使用w uptime vmstat top sar nload 等命令查看系统负载
  • 原文地址:https://www.cnblogs.com/Narh/p/10691259.html
Copyright © 2011-2022 走看看