zoukankan      html  css  js  c++  java
  • bzoj 2865 字符串识别 —— 后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865

    唯一出现的子串就是每个后缀除去和别的后缀最长的 LCP 之外的前缀;

    所以用这个更新一段区间的答案,可以用线段树维护;

    在 sa[i] ~ sa[i]+LCP+1 位置的答案由 LCP+1 更新,sa[i]+LCP+1 之后的位置就更新一个位置 ps 表示从 ps 到本位置的子串也可以;

    最后两个取min即可;

    注意如果整个后缀就是 LCP,那么就不能更新了;

    线段树中 ps 的初值是0,取答案时注意判掉0。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define mid ((l+r)>>1)
    using namespace std;
    int const xn=5e5+5,xm=(xn<<1);
    int n,m,rk[xn],sa[xn],tax[xn],tp[xn],ht[xn];
    int cnt=1,ls[xm],rs[xm],len[xm],ps[xm];
    char s[xn];
    void Rsort()
    {
      for(int i=1;i<=m;i++)tax[i]=0;
      for(int i=1;i<=n;i++)tax[rk[tp[i]]]++;
      for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
      for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
    }
    void work()
    {
      for(int i=1;i<=n;i++)rk[i]=s[i],tp[i]=i;
      Rsort();
      for(int k=1;k<=n;k<<=1)
        {
          int num=0;
          for(int i=n-k+1;i<=n;i++)tp[++num]=i;
          for(int i=1;i<=n;i++)
        if(sa[i]>k)tp[++num]=sa[i]-k;
          Rsort(); memcpy(tp,rk,sizeof rk);
          rk[sa[1]]=1; num=1;
          for(int i=2;i<=n;i++)
        rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?num:++num;
          if(num==n)break;
          m=num;
        }
    }
    void get()
    {
      int k=0;
      for(int i=1;i<=n;i++)
        {
          if(rk[i]==1)continue;
          if(k)k--; int j=sa[rk[i]-1];
          while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
          ht[rk[i]]=k;
        }
    }
    void build(int x,int l,int r)
    {
      len[x]=n+1;
      if(l==r)return;
      ls[x]=++cnt; build(ls[x],l,mid);
      rs[x]=++cnt; build(rs[x],mid+1,r);
    }
    void update(int x,int l,int r,int L,int R,int v)
    {
      if(l>=L&&r<=R){len[x]=min(len[x],v); return;}
      if(mid>=L)update(ls[x],l,mid,L,R,v);
      if(mid<R)update(rs[x],mid+1,r,L,R,v);
    }
    void chg(int x,int l,int r,int L,int R,int v)
    {
      if(l>=L&&r<=R){ps[x]=max(ps[x],v); return;}
      if(mid>=L)chg(ls[x],l,mid,L,R,v);
      if(mid<R)chg(rs[x],mid+1,r,L,R,v);
    }
    int query(int x,int l,int r,int pos,int v)
    {
      v=min(v,len[x]);
      if(l==r)return v;
      if(pos<=mid)return query(ls[x],l,mid,pos,v);
      else return query(rs[x],mid+1,r,pos,v);
    }
    int ask(int x,int l,int r,int pos,int v)
    {
      v=max(v,ps[x]);
      if(l==r)return v;
      if(pos<=mid)return ask(ls[x],l,mid,pos,v);
      else return ask(rs[x],mid+1,r,pos,v);
    }
    int main()
    {
      scanf("%s",s+1); n=strlen(s+1); m=125;
      work(); get(); build(1,1,n);
      for(int i=1;i<=n;i++)
        {
          int lcp=max(ht[i],ht[i+1]);
          if(sa[i]+lcp<=n)update(1,1,n,sa[i],sa[i]+lcp,lcp+1);//
          if(sa[i]+lcp+1<=n)chg(1,1,n,sa[i]+lcp+1,n,sa[i]);
        }
      for(int i=1;i<=n;i++)
        {
          int t=query(1,1,n,i,n+1),p=ask(1,1,n,i,0);
          if(p==0)printf("%d
    ",t);//!
          else printf("%d
    ",min(t,i-p+1));
        }
      return 0;
    }
  • 相关阅读:
    HDU 5912 Fraction (模拟)
    CodeForces 722C Destroying Array (并查集)
    CodeForces 722B Verse Pattern (水题)
    CodeForces 722A Broken Clock (水题)
    CodeForces 723D Lakes in Berland (dfs搜索)
    CodeForces 723C Polycarp at the Radio (题意题+暴力)
    CodeForces 723B Text Document Analysis (水题模拟)
    CodeForces 723A The New Year: Meeting Friends (水题)
    hdu 1258
    hdu 2266 dfs+1258
  • 原文地址:https://www.cnblogs.com/Zinn/p/10088058.html
Copyright © 2011-2022 走看看