zoukankan      html  css  js  c++  java
  • bzoj 2555 SubString——后缀自动机+LCT

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

    要维护 right 集合的大小。因为 fa 会变,且 fa 构成一棵树,所以考虑用 LCT 来维护……

    和平常写的 LCT 不太一样。因为要的值是原树上子树里的值,所以没有 makeroot ,splay 里不维护 splay 里的子树信息,只维护加法标记,表示 link 一下就给原树的自己到根的那条链上的所有点加了自己的值。cut 就是减掉自己的值。所以 query 或者 splay 的时候先把自己这棵 splay 里自己到根的路径 pshd 一遍,且没有 pshp 什么的。而且 link 时要区分两个点哪个是原树上的父亲。

    不知怎么看出字符只有大写字母的。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1200005,K=30,M=3e6+5;
    int cnt=1,lst=1,go[N][K],fa[N],l[N],mask;
    int c[N][2],pre[N],sta[N],top,sm[N],tg[N];
    char ch[M];
    void decodeWithMask(int n,int mask)
    {
      for(int i=0;i<n;i++)
        {
          mask=(mask*131+i)%n;
          swap(ch[i],ch[mask]);
        }
    }
    bool isroot(int x){return c[pre[x]][0]!=x&&c[pre[x]][1]!=x;}
    void pshd(int x)
    {
      if(!tg[x])return;int ls=c[x][0],rs=c[x][1];
      sm[ls]+=tg[x];tg[ls]+=tg[x];sm[rs]+=tg[x];tg[rs]+=tg[x];
      tg[x]=0;
    }
    void Pshd(int x)
    {
      sta[top=1]=x;
      for(;!isroot(x);x=pre[x])sta[++top]=pre[x];
      for(int i=top;i;i--)pshd(sta[i]);
    }
    void rotate(int x)
    {
      int y=pre[x],z=pre[y];
      if(!isroot(y))c[z][y==c[z][1]]=x;
      pre[x]=z;
      int d=(x==c[y][1]);
      pre[c[x][!d]]=y; pre[y]=x;
      c[y][d]=c[x][!d]; c[x][!d]=y;
    }
    void splay(int x)
    {
      Pshd(x);
      while(!isroot(x))
        {
          int y=pre[x],z=pre[y];
          if(!isroot(y))
        {
          if((y==c[z][0])^(x==c[y][0]))rotate(x);
          else rotate(y);
        }
          rotate(x);
        }
    }
    void access(int x)
    {
      for(int t=0;x;splay(x),c[x][1]=t,t=x,x=pre[x]);
    }
    void link(int x,int y)
    {
      pre[y]=x;access(x);splay(x);
      sm[x]+=sm[y]; tg[x]+=sm[y];//tg:pre of x all added
    }
    void cut(int x)
    {
      access(x);splay(x);
      sm[c[x][0]]-=sm[x]; tg[c[x][0]]-=sm[x];//tg:pre of x all declined
      pre[c[x][0]]=0; c[x][0]=0;
    }
    void add(int w)
    {
      int p=lst,np=++cnt;lst=np;l[np]=l[p]+1;sm[np]=1;
      for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
      if(!p)fa[np]=1,link(1,np);
      else
        {
          int q=go[p][w];
          if(l[q]==l[p]+1)fa[np]=q,link(q,np);
          else
        {
          int nq=++cnt;l[nq]=l[p]+1;
          cut(q);link(fa[q],nq);link(nq,q);link(nq,np);///
          fa[nq]=fa[q];fa[q]=nq;fa[np]=nq;//after link&cut !
          memcpy(go[nq],go[q],sizeof go[q]);
          for(;go[p][w]==q;p=fa[p])go[p][w]=nq;
        }
        }
    }
    int query(int len)
    {
      int cr=1;
      for(int i=0;i<len;i++)
        {
          if(!go[cr][ch[i]-'A'+1])return 0;
          cr=go[cr][ch[i]-'A'+1];
        }
      Pshd(cr); return sm[cr];
    }
    int main()
    {
      int Q;scanf("%d",&Q);scanf("%s",ch);
      int n=strlen(ch);for(int i=0;i<n;i++)add(ch[i]-'A'+1);
      char tch[10];
      while(Q--)
        {
          scanf("%s",tch);scanf("%s",ch);n=strlen(ch);
          decodeWithMask(n,mask);
          if(tch[0]=='A')
        {
          for(int i=0;i<n;i++)add(ch[i]-'A'+1);
        }
          else
        {
          int d=query(n);printf("%d
    ",d);
          mask^=d;
        }
        }
      return 0;
    }
  • 相关阅读:
    Axure 实现数字自动加键功能(点击“+”数字加1,点击“-”数字减1)
    Axure 实现批量的勾选和反选
    传说中的AutoCAD公司
    Autodesk 最新开发技术研讨会-北京-上海-武汉-成都-西安-PPT下载
    发布App,赢iPad mini + 美金100$
    无插件的大模型浏览器Autodesk Viewer开发培训-武汉-2014年8月28日 9:00 – 12:00
    为Autodesk Viewer添加自定义工具条的更好方法
    为Autodesk Viewer添加自定义工具条
    Autodesk 最新开发技术研讨会 -8月22日-Autodesk北京办公室
    请保护我们的地球
  • 原文地址:https://www.cnblogs.com/Narh/p/10107574.html
Copyright © 2011-2022 走看看