LCT复习之bzoj2555: SubString

题意

懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。

题解

直接SAM
然后考虑到不断地加边删边,容易想到用LCT来维护parent树
然后每一次就相当于是把这个点到根路径上全部点都加上或减去某个值
lazy标记打一打就好了
还是挺好写的
但是由于我还是太SB了。。所以还是调了挺久

CODE:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
const int N=600005*2;
int T;
int len,tot,last;
struct qq
{
       int par,son[26],step;
}s[N];//SAM
struct qr
{
   int c,fa,rev,son[2],lzy;//这个节点的值   父亲   区间加 
   void bt (int x)
   {
      son[0]=son[1]=fa=rev=lzy=0;
      c=x;
   };
}tr[N];//LCT
void add (int x,int y){tr[x].lzy+=y;}
bool is_root (int x)
{
    int fa=tr[x].fa;
    if (tr[fa].son[0]==x) return false;
    if (tr[fa].son[1]==x) return false;
    return true;
}
void push_down (int x)
{
    int s1=tr[x].son[0],s2=tr[x].son[1];
    if (tr[x].rev)
    {
        swap(tr[x].son[0],tr[x].son[1]);
        if (s1!=0)tr[s1].rev^=1;
        if (s2!=0)tr[s2].rev^=1;
        tr[x].rev^=1;
    }
    if (tr[x].lzy!=0)
    {
        tr[x].c+=tr[x].lzy;
        if (s1!=0) add(s1,tr[x].lzy);
        if (s2!=0) add(s2,tr[x].lzy);
        tr[x].lzy=0;
    }
}
void pre (int x)
{
    if (!is_root(x)) pre(tr[x].fa);
    push_down(x);
}
void rotate (int x)
{
    int y=tr[x].fa,z=tr[y].fa,r,R;
    int w=(tr[y].son[0]==x);

    r=tr[x].son[w];R=y;
    tr[R].son[1-w]=r;
    if (r!=0) tr[r].fa=R;

    r=x;R=z;
    if (!is_root(y))
    {
        if (tr[R].son[0]==y) tr[R].son[0]=r;
        else tr[R].son[1]=r;
    }
    tr[r].fa=R;

    r=y;R=x;
    tr[R].son[w]=r;
    tr[r].fa=R;

}
void splay (int x)
{
    pre(x);
    while (!is_root(x))
    {
        int y=tr[x].fa,z=tr[y].fa;
        if (!is_root(y))
        {
            if ((tr[z].son[0]==y)==(tr[y].son[0]==x)) rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
}
void access (int x)
{
    int Last=0;
    while (x!=0)
    {
        splay(x);
        tr[x].son[1]=Last;
        Last=x;
        x=tr[x].fa;
    }
}
void link (int x,int y)//x向y连边 
{
    tr[y].fa=x;
    access(x);
    splay(x);
    add(x,tr[y].c);
}
void cut (int x)
{
    access(x);
    splay(x);
    add(tr[x].son[0],-tr[x].c);
    tr[x].son[0]=tr[tr[x].son[0]].fa=0;
}
void ins (int x)
{
    int np=++tot,p=last;
    s[np].step=s[p].step+1;tr[np].bt(1);
    while (p!=0&&s[p].son[x]==0)    s[p].son[x]=np,p=s[p].par;
    if (p==0)   {s[np].par=1;link(1,np);}
    else
    {
        int q=s[p].son[x];
        if (s[q].step==s[p].step+1) s[np].par=q,link(q,np);
        else
        {
            int nq=++tot;tr[nq].bt(0);
            s[nq]=s[q];
            link(s[nq].par,nq);
            s[nq].step=s[p].step+1;
            cut(q);
            link(nq,q);link(nq,np);
            s[q].par=s[np].par=nq;
            while (p!=0&&s[p].son[x]==q) s[p].son[x]=nq,p=s[p].par;
        }
    }
    last=np;
}
char ss[N];
int main()
{
    last=tot=1;
    scanf("%d",&T);
    scanf("%s",ss);len=strlen(ss);
    for (int u=0;u<len;u++) ins(ss[u]-'A');
    int mask=0;
    while (T--)
    {
          char SS[10];
          scanf("%s %s",SS,ss);
          len=strlen(ss);
          int tmp=mask;
          for (int u=0;u<len;u++)
          {
              tmp=(tmp*131+u)%len;
              swap(ss[tmp],ss[u]);
          }
          if (SS[0]=='A')
             for (int u=0;u<len;u++) ins(ss[u]-'A');
          else
          {
              int x=1;
              bool tf=false;
              for (int u=0;u<len;u++)
              {
                  int c=ss[u]-'A';
                  if (s[x].son[c]==0) {printf("0\n");tf=true;break;}
                  x=s[x].son[c];
              }
              if (!tf)
              {
                    splay(x);
                    printf("%d\n",tr[x].c);
                    mask^=tr[x].c;
              }
          }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值