zoukankan      html  css  js  c++  java
  • bzoj 4556 字符串 —— 后缀数组+主席树

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

    就是找一个 rk 在一段区间内的前驱和后继;

    由于 LCP 还有区间长度的限制,所以可以先二分答案!

    然后直接建立 rk 的主席树,查询即可。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define mid ((l+r)>>1)
    using namespace std;
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    int Min(int x,int y){return x<y?x:y;}
    int Max(int x,int y){return x>y?x:y;}
    int const xn=1e5+5,xm=1e5*18;
    int n,m,rk[xn],tp[xn],sa[xn],tax[xn],ht[xn][20],bin[20],bit[xn];
    int cnt,rt[xn],ls[xm],rs[xm],sum[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 init()
    {
      for(int i=1;i<=n;i++)tp[i]=i,rk[i]=s[i];
      m=125; 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(); swap(rk,tp);
          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 geth()
    {
      int k=0;
      for(int i=1;i<=n;i++)
        {
          if(rk[i]==1)continue;//continue
          if(k)k--; int j=sa[rk[i]-1];
          while(s[i+k]==s[j+k]&&i+k<=n&&j+k<=n)k++;
          ht[rk[i]][0]=k;
        }
      bin[0]=1; for(int i=1;i<20;i++)bin[i]=(bin[i-1]<<1);
      bit[1]=0; for(int i=2;i<=n;i++)bit[i]=bit[i>>1]+1;
      for(int i=1;i<20;i++)
        for(int j=1;j<=n&&j+bin[i]-1<=n;j++)
          ht[j][i]=Min(ht[j][i-1],ht[j+bin[i-1]][i-1]);
    }
    int getlcp(int x,int y)//rk
    {
      if(x==y)return n-sa[x]+1;
      if(x>y)swap(x,y); x++;
      int r=bit[y-x+1];
      return Min(ht[x][r],ht[y-bin[r]+1][r]);
    }
    void build(int &x,int y,int l,int r,int v)
    {
      x=++cnt; ls[x]=ls[y]; rs[x]=rs[y]; sum[x]=sum[y]+1;
      if(l==r)return;
      if(v<=mid)build(ls[x],ls[y],l,mid,v);
      else build(rs[x],rs[y],mid+1,r,v);
    }
    int findl(int x,int y,int l,int r)
    {
      if(!(sum[x]-sum[y]))return -1;
      if(l==r)return l;
      if(sum[ls[x]]-sum[ls[y]])return findl(ls[x],ls[y],l,mid);
      return findl(rs[x],rs[y],mid+1,r);
    }
    int findr(int x,int y,int l,int r)
    {
      if(!(sum[x]-sum[y]))return -1;
      if(l==r)return l;
      if(sum[rs[x]]-sum[rs[y]])return findr(rs[x],rs[y],mid+1,r);
      return findr(ls[x],ls[y],l,mid);
    }
    int queryp(int x,int y,int l,int r,int v)
    {
      if(!(sum[x]-sum[y]))return -1;
      if(l==r)return l;
      if(v<=mid)return queryp(ls[x],ls[y],l,mid,v);
      else
        {
          int tmp=queryp(rs[x],rs[y],mid+1,r,v);
          if(tmp!=-1)return tmp;
          return findr(ls[x],ls[y],l,mid);
        }
    }
    int querys(int x,int y,int l,int r,int v)
    {
      if(!(sum[x]-sum[y]))return -1;
      if(l==r)return l;
      if(v>mid)return querys(rs[x],rs[y],mid+1,r,v);
      else
        {
          int tmp=querys(ls[x],ls[y],l,mid,v);
          if(tmp!=-1)return tmp;
          return findl(rs[x],rs[y],mid+1,r);
        }
    }
    bool ck(int a,int b,int x,int v)
    {
      int L=a,R=b-x+1;
      int pr=queryp(rt[R],rt[L-1],1,n,v),sc=querys(rt[R],rt[L-1],1,n,v);
      int len=0;
      if(pr!=-1)len=Max(len,getlcp(pr,v));
      if(sc!=-1)len=Max(len,getlcp(sc,v));
      return len>=x;
    }
    int main()
    {
      n=rd(); int Q=rd();
      scanf("%s",s+1); init(); geth();
      for(int i=1;i<=n;i++)build(rt[i],rt[i-1],1,n,rk[i]);
      for(int i=1,a,b,c,d;i<=Q;i++)
        {
          a=rd(); b=rd(); c=rd(); d=rd();
          int l=0,r=Min(b-a+1,d-c+1),res;
          while(l<=r)
        {
          if(ck(a,b,mid,rk[c]))res=mid,l=mid+1;
          else r=mid-1;
        }
          printf("%d
    ",res);
        }
      return 0;
    }
  • 相关阅读:
    OCP-1Z0-053-V12.02-15题
    Boost.Asio性能测试
    使用asio搭建服务器
    boost::asio::ip::tcp::socket is connected?(如何知道socket的链接是链接或断开?)
    boost::async_read_some连续接收数据
    基于boost asio实现的支持ssl的通用socket框架
    Boost.Asio的使用技巧
    Matlab基本函数-expm函数
    Matlab基本函数-exp函数
    OCP-1Z0-053-V12.02-337题
  • 原文地址:https://www.cnblogs.com/Zinn/p/10317432.html
Copyright © 2011-2022 走看看