zoukankan      html  css  js  c++  java
  • luogu P2336 [SCOI2012]喵星球上的点名

    传送门

    这题tm把AC自动机叉掉了,,,

    只能考虑别的做法

    把所有串连在一起,不同串的交界处加入一些不同的字符,然后求出sa数组和height数组,现在一个询问的答案就是和那个询问串的lcp正好为询问串长度的原串个数,而这在把后缀排好序后是一个区间,每个原串答案为包含这个原串的某个点的区间个数

    如果将每个原串的点染成对应编号的颜色,那么现在求的是每个区间包含的点的颜色种类和每种点被多少个区间包含,可以用莫队实现,前者就是HH的项链,后者可以在每种颜色对第一种答案加上贡献时对其答案加上剩余询问个数,在对第一种答案减去贡献时对其答案减去剩余询问个数

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define LL long long
    #define il inline
    #define re register
    #define db double
    
    using namespace std;
    const int N=400000+10,M=100000+10;
    il int rd()
    {
      int x=0,w=1;char ch=0;
      while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
      return x*w;
    }
    int n,l1,l2,m=10000;
    int rk[N],sa[N],wr[N],bk[N],wx[N],he[N];
    int cc[N];
    il bool cmp(int a,int b,int j){return wr[a]==wr[b]&&wr[a+j]==wr[b+j];}
    il void gSA(int m)
    {
      for(int i=1;i<=n;++i) ++bk[rk[i]=cc[i]];
      for(int i=1;i<=m;++i) bk[i]+=bk[i-1];
      for(int i=n;i;--i) sa[bk[rk[i]]--]=i;
      int tp,j=1,p=0;
      while(p<n)
        {
          tp=0;
          for(int i=n-j+1;i<=n;++i) wx[++tp]=i;
          for(int i=1;i<=n;++i) if(sa[i]>j) wx[++tp]=sa[i]-j;
          for(int i=1;i<=n;++i) wr[i]=rk[wx[i]];
          for(int i=0;i<=m;++i) bk[i]=0;
          for(int i=1;i<=n;++i) ++bk[wr[i]];
          for(int i=1;i<=m;++i) bk[i]+=bk[i-1];
          for(int i=n;i;--i) sa[bk[wr[i]]--]=wx[i];
          for(int i=1;i<=n;++i) wr[i]=rk[i];
          rk[sa[1]]=p=1;
          for(int i=2;i<=n;++i) rk[sa[i]]=p+=(cmp(sa[i],sa[i-1],j)^1);
          m=p,j<<=1;
        }
      for(int i=1,j;i<=n;++i)
        {
          he[rk[i]]=he[rk[i-1]]?he[rk[i-1]]-1:0;
          j=sa[rk[i]-1];
          while(cc[i+he[rk[i]]]==cc[j+he[rk[i]]]) ++he[rk[i]];
        }
    }
    int p[M][2],w[M],len[M],be[N],b2[N],cn[M],na,a1[M],a2[M];
    il void ad(int x,int res)
    {
      ++cn[b2[sa[x]]];
      if(b2[sa[x]]&&cn[b2[sa[x]]]==1) ++na,a2[b2[sa[x]]]+=res;
    }
    il void dl(int x,int res)
    {
      --cn[b2[sa[x]]];
      if(b2[sa[x]]&&cn[b2[sa[x]]]==0) --na,a2[b2[sa[x]]]-=res;
    }
    int mi[N][20],hbt[N];
    il int gmin(int l,int r)
    {
      if(l>r) swap(l,r);
      ++l;
      if(l>r) return -1;
      int z=hbt[r-l+1];
      return min(mi[l][z],mi[r-(1<<z)+1][z]);
    }
    struct qu
    {
      int l,r,id;
      bool operator < (const qu bb) const {return (be[l]^be[bb.l])?l<bb.l:r<bb.r;}
    }qq[M];
    
    int main()
    {
      l1=rd(),l2=rd();
      cc[0]=m;
      for(int i=1;i<=l1;++i)
        {
          p[i][0]=n+1;
          int k=rd();
          while(k--) cc[++n]=rd();
          cc[++n]=++m;
          k=rd();
          while(k--) cc[++n]=rd();
          cc[++n]=++m;
          p[i][1]=n-1;
        }
      for(int i=1;i<=l2;++i)
        {
          w[i]=n+1;
          int k=len[i]=rd();
          while(k--) cc[++n]=rd();
          cc[++n]=++m;
        }
      --n;
      gSA(m);
      int sqrtn=sqrt(n),lz=log2(n);
      hbt[0]=-1;
      for(int i=0;i<=n;++i) be[i]=i/sqrtn;
      for(int i=1;i<=n;++i) hbt[i]=hbt[i-1]+((i&(-i))==i);
      for(int i=1;i<=n;++i)
        mi[i][0]=he[i];
      for(int j=1;j<=lz;++j)
        for(int i=1;i<=n-(1<<(j-1));++i)
          mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
      for(int i=1;i<=l2;++i)
        {
          qq[i].l=qq[i].r=rk[w[i]],qq[i].id=i;
          int l=1,r=rk[w[i]]-1;
          while(l<=r)
            {
              int mid=(l+r)>>1;
              if(gmin(mid,rk[w[i]])==len[i]) qq[i].l=mid,r=mid-1;
              else l=mid+1;
            }
          l=rk[w[i]]+1,r=n;
          while(l<=r)
            {
              int mid=(l+r)>>1;
              if(gmin(rk[w[i]],mid)==len[i]) qq[i].r=mid,l=mid+1;
              else r=mid-1;
            }
        }
      sort(qq+1,qq+l2+1);
      for(int i=1,j=1;;++i)
        {
          while(j<=l1&&i>p[j][1]) ++j;
          if(j>l1) break;
          b2[i]=(i>=p[j][0]?j:0);
        }
      for(int i=1,l=1,r=0;i<=l2;++i)
        {
          while(r<qq[i].r) ++r,ad(r,l2-i+1);
          while(r>qq[i].r) dl(r,l2-i+1),--r;
          while(l<qq[i].l) dl(l,l2-i+1),++l;
          while(l>qq[i].l) --l,ad(l,l2-i+1);
          a1[qq[i].id]=na;
        }
      for(int i=1;i<=l2;++i) printf("%d
    ",a1[i]);
      for(int i=1;i<=l1;++i) printf("%d ",a2[i]);
      return 0;
    }
    

    推荐去dd我的xzz巨佬博客看更优秀的题解

  • 相关阅读:
    《数据结构》张明瑞 清华大学 计算机科学与技术专业 大二
    Android studio 快捷键
    android下的样式
    Android照片墙应用实现,再多的图片也不怕崩溃
    菜单
    Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能
    自动文本提示控件
    Android高效加载大图、多图解决方案,有效避免程序OOM
    notification+service实现消息推送
    常见对话框
  • 原文地址:https://www.cnblogs.com/smyjr/p/10100311.html
Copyright © 2011-2022 走看看