bzoj2555: SubString

题目大意

你需要在线维护两种操作:
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)

题解

当时学SAM的时候一直不敢做这题,因为我不会LCT。。
听说奥爷爷有splay而非LCT的做法,没去学
这题对于我来说唯一的问题就是怎么知道一个节点子树的总和。。
我们不妨换一个思路,我们一个点维护的不是他Splay的信息,直接就是他原树上的总和
当我们有一个Cut操作时,如果是将x变为一个新的联通块,那就相当于是将root到x的路径全部减去x的值。。
这个只要分离出root和x的路径,然后打个标记就好了
Link的时候也是同样道理
具体看代码

#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 pre,son[26],step;
}s[N];
struct qr
{
       int d,fa,rev,son[2],u;
       void bt (int x)
       {
          son[0]=son[1]=fa=rev=0;
          d=x;
       };
}tr[N];//LCT
bool Is_root(int x)
{
  if((tr[tr[x].fa].son[0]!=x)&&(tr[tr[x].fa].son[1]!=x)) return true;
  return false;
}
void update (int x)
{
    int s1=tr[x].son[0],s2=tr[x].son[1];
    if(tr[x].u!=0)
    {
        int u=tr[x].u;
        tr[x].u=0;
        tr[s1].d+=u;tr[s2].d+=u;
        tr[s1].u+=u;tr[s2].u+=u;
    }
    if (tr[x].rev)
    {
        tr[x].rev=false;
        tr[s1].rev^=1;tr[s2].rev^=1;
        swap(tr[x].son[0],tr[x].son[1]);
    }
}
void Rotate(int x)
{
  int y=tr[x].fa; int z=tr[y].fa;
  int a=tr[y].son[1]==x; int b=tr[z].son[1]==y;
  int g=tr[x].son[a^1];
  if(!Is_root(y)) tr[z].son[b]=x; tr[x].fa=z;
  tr[x].son[a^1]=y; tr[y].fa=x;
  tr[y].son[a]=g; if(g) tr[g].fa=y;
  update(y);
}
stack<int>S;
void Preserve(int x)
{
  while(!Is_root(x)) S.push(x),x=tr[x].fa;
  S.push(x);
  while(!S.empty()) update(S.top()),S.pop();
}
void Splay(int x)
{
  Preserve(x);
  while(!Is_root(x))
  {
    int y=tr[x].fa; int z=tr[y].fa;
    int a=tr[y].son[1]==x; int b=tr[z].son[1]==y;
    if(Is_root(y)) Rotate(x);
    else
    {
      if(a==b) Rotate(y);
      else Rotate(x);
      Rotate(x);
    }
  }update(x);
}
void Access (int x)
{
     int last=0;
     while (x!=0)
     {
           Splay(x);
           tr[x].son[1]=last;
           update(x);
           last=x;
           x=tr[x].fa;  
     }  
}
void make_root(int x)
{
     Access(x);
     Splay(x);
     tr[x].rev^=1;  
}
void Split (int x,int y)
{
    make_root(x);
    Access(y);
    Splay(y);
}
void Link (int x,int y)
{
     make_root(y);
     tr[y].fa=x;
     Split(1,x);
     tr[x].u+=tr[x].d;
}
void Cut (int x,int y)//注意,我们是让深度深的连向深度浅的,所以就是说x和这棵树脱离了 
{
    Split(1,x);
    tr[x].u-=tr[x].d;
    Split(x,y);
    tr[x].fa=tr[y].son[0]=0;
    update(y);
}
int find_root(int x)
{
    Access(x);
    Splay(x);
    while (tr[x].son[0]!=0)  x=tr[x].son[0];
    return x;
}
void ins (int x)
{
    //printf("%d\n",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].pre;
     if (p==0) s[np].pre=1,Link(np,1);
     else
     {
         int q=s[p].son[x];
         if (s[q].step==s[p].step+1) s[np].pre=q,Link(np,q);
         else
         {
             int nq=++tot;
             tr[nq].bt(0);
             s[nq]=s[q];
             Link(nq,s[q].pre);/*****/
             s[nq].step=s[p].step+1;
             Cut(q,s[q].pre);/*****/
             s[q].pre=s[np].pre=nq;
             Link(q,nq);Link(np,nq);/******/
             while (p!=0&&s[p].son[x]==q) s[p].son[x]=nq,p=s[p].pre;  
         }
     }
     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)
              {
                 make_root(1);
                 Access(x);Splay(x);
                 printf("%d\n",tr[x].d);
                 mask^=tr[x].d;
              }
          }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值