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

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

    建立后缀自动机,就可以直接加入新串了;

    出现次数就是 Right 集合的大小,需要查询 Parent 树上的子树和;

    所以可以用 LCT 维护 Parent 树,因为 Parent 树是有根树所以不需要 makeroot;

    代码中的两种 cut 写法都可以,其实这里的 splay 节点上记的 siz 值不是 splay 子树里的而是原子树( Parent 树上)里的;

    注意读入的函数内不改变 mask -_-

    splay 用栈时不要改变 x !

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const xn=1200005,xm=3e6+5;
    int fa[xn],lst=1,cnt=1,l[xn],go[xn][30],siz[xn];
    int pre[xn],c[xn][2],sta[xn],top,lzy[xn],mask;
    char dc[10],s[xm];
    void turn(int x,int w){siz[x]+=w; lzy[x]+=w;}//
    bool isroot(int x){return c[pre[x]][0]!=x&&c[pre[x]][1]!=x;}
    void pushdown(int x)
    {
      if(!lzy[x])return;
      int ls=c[x][0],rs=c[x][1];
      turn(ls,lzy[x]); turn(rs,lzy[x]);
      lzy[x]=0;
    }
    void rotate(int x)
    {
      int y=pre[x],z=pre[y],d=(c[y][1]==x);
      if(!isroot(y))c[z][c[z][1]==y]=x;
      pre[x]=z; pre[y]=x; pre[c[x][!d]]=y;
      c[y][d]=c[x][!d]; c[x][!d]=y;
    }
    void splay(int x)
    {
      sta[top=1]=x;
      //while(!isroot(x))sta[++top]=pre[x],x=pre[x];//don't change x!!
      for(int i=x;!isroot(i);i=pre[i])sta[++top]=pre[i];
      while(top)pushdown(sta[top--]);
      
      while(!isroot(x))
        {
          int y=pre[x],z=pre[y];
          if(!isroot(y))
        {
          if((c[y][0]==x)^(c[z][0]==y))rotate(x);
          else rotate(y);
        }
          rotate(x);
        }
    }
    void access(int x)
    {
      for(int t=0;x;c[x][1]=t,t=x,x=pre[x])splay(x);
    }
    void link(int x,int f)
    {
      pre[x]=f; access(f); splay(f); turn(f,siz[x]);//line to root
    }
    void Cut(int x)
    {
      access(x); splay(x); turn(c[x][0],-siz[x]); pre[c[x][0]]=0; c[x][0]=0;//c[x][0]:parent
    }
    void cut(int x)//
    {
      access(x); int y=fa[x]; splay(y);//
      turn(y,-siz[x]); fa[x]=0; c[y][1]=0;
    }
    void add(int w)
    {
      int p=lst,np=++cnt; lst=np; l[np]=l[p]+1; siz[np]=1;
      for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
      if(!p)fa[np]=1,link(np,1);
      else
        {
          int q=go[p][w];
          if(l[q]==l[p]+1)fa[np]=q,link(np,q);
          else
        {
          int nq=++cnt; l[nq]=l[p]+1;
          memcpy(go[nq],go[q],sizeof go[q]);
          fa[nq]=fa[q]; link(nq,fa[q]);
          fa[np]=nq; link(np,nq);
          cut(q); fa[q]=nq; link(q,nq);
          for(;go[p][w]==q;p=fa[p])go[p][w]=nq;
        }
        }
    }
    int query(int l)
    {
      int p=1;//1
      for(int i=0;i<l;i++)
        {
          if(!go[p][s[i]-'A'])return 0;
          p=go[p][s[i]-'A'];
        }
      access(p); splay(p); return siz[p];//
    }
    int main()
    {
      int Q; scanf("%d",&Q);
      scanf("%s",s+1); int l=strlen(s+1);
      for(int i=1;i<=l;i++)add(s[i]-'A');
      for(int i=1;i<=Q;i++)
        {
          scanf("%s",dc); scanf("%s",s); l=strlen(s);
          int tmp=mask;//!!-_-
          for(int j=0;j<l;j++)
        {
          tmp=(tmp*131+j)%l;
          char t=s[j]; s[j]=s[tmp]; s[tmp]=t;
        }
          if(dc[0]=='A')for(int j=0;j<l;j++)add(s[j]-'A');
          else
        {
          int ans=query(l); mask^=ans;
          printf("%d
    ",ans);
        }
        }
      return 0;
    }
  • 相关阅读:
    List遍历时删除与迭代器(Iterator)解惑
    从一次“并发修改字段业务”引出多版本并发控制与InnoDB锁
    RocketMQ存储机制与确认重传机制
    Java中的锁
    jmeter在non-GUI模式下用法
    Java SPI机制简述
    深拷贝、浅拷贝与Cloneable接口
    Java中的小数运算与精度损失
    java中的枚举类
    SpringBoot是如何实现自动配置的
  • 原文地址:https://www.cnblogs.com/Zinn/p/10107136.html
Copyright © 2011-2022 走看看