BZOJ2555 SubString 后缀自动机+LCT

题意:给一个串,支持

1.询问一个串在当前串中的出现次数

2.在串尾加一个字符串

强制在线

Sol:

如果没有添加操作,答案就是将给定串在SAM上跑到的最终状态的Right集合大小(到不了就是0)

Right集合大小可用Parent树算

现在有了添加,Parent树是会变化(加边或删边)

容易想到可用LCT维护Parent树形态

每个点影响的范围是她到根的一条链,影响是链上加自己的权值

代码题QAQ

Hint:字符集大小其实是2 , 解密函数中mask是局部变量,不会修改全局的mask

Code:

#include<bits/stdc++.h>
#define debug(x) cout<<#x<<"="<<x<<endl
#define PAD(x,y) memset(x,y,sizeof x)
#define CPY(x,y) memcpy(x,y,sizeof x)
using namespace std;
const int maxn = 600009, alpha = 2;
int tot,root,last;
struct state
{
    int son[alpha];
    int mx,siz,par;
}node[maxn<<1];
int son[maxn<<1][2],fa[maxn<<1],val[maxn<<1],tag[maxn<<1],S[maxn<<1];
bool rev[maxn<<1];
char str[3000009],opt[100];
int m,mask;

void init(){tot=last=root=1;}

void decode(char *s)
{
    int len=strlen(s),tmp=mask;
    for(int i=0;i<len;i++)
    {
	  tmp=(tmp*131+i)%len;
	  swap(s[i],s[tmp]);
    }
}

inline bool is_root(int x){return (son[fa[x]][0]!=x)&&(son[fa[x]][1]!=x);}
void down(int x)
{
    if(tag[x])
    {
	  tag[son[x][0]]+=tag[x];val[son[x][0]]+=tag[x];
	  tag[son[x][1]]+=tag[x];val[son[x][1]]+=tag[x];
	  tag[x]=0;
    }
    if(rev[x])
    {
	  rev[son[x][0]]^=1;
	  rev[son[x][1]]^=1;
	  swap(son[x][0],son[x][1]);
	  rev[x]=0;
    }
}
void make_plus(int x,int y){val[x]+=y;tag[x]+=y;}
void rotate(int x)
{
    int y=fa[x],z=fa[y],l,r;
    if(son[y][0]==x) l=0;else l=1;r=l^1;
    if(!is_root(y)) if(son[z][0]==y) son[z][0]=x;
			  else son[z][1]=x;
    fa[x]=z;fa[y]=x;fa[son[x][r]]=y;
    son[y][l]=son[x][r];son[x][r]=y;
}
void splay(int x)
{
    int y=x,z,top=0;
    while(!is_root(y)) S[++top]=y,y=fa[y];S[++top]=y;
    while(top) down(S[top]),top--;
    while(!is_root(x))
    {
	  y=fa[x];z=fa[y];
	  if(!is_root(y)) if((son[y][0]==x)^(son[z][0]==y)) rotate(x);
				else rotate(y);
	  rotate(x);
    }
}
void access(int x)
{
    int t=0;
    while(x)
    {
	  splay(x);
	  son[x][1]=t;
	  t=x;x=fa[x];
    }
}
void make_root(int x)
{
    access(x);splay(x);rev[x]^=1;
}
void link(int x,int y)
{
    make_root(x);fa[x]=y;
    make_root(root);
    access(x);splay(x);
    make_plus(son[x][0],val[x]);
}
void cut(int x,int y)
{
    make_root(root);
    access(x);splay(x);
    make_plus(son[x][0],-val[x]);
    make_root(x);access(y);splay(y);son[y][0]=fa[x]=0;
}

void extend(int x)
{
    int p=last,np=++tot;
    node[np].mx=node[p].mx+1;
    node[np].siz=1;val[np]=1;
    while(p&&node[p].son[x]==0)
	  node[p].son[x]=np,p=node[p].par;
    if(p==0) node[np].par=root,link(np,root);
    else
    {
	  int q=node[p].son[x];
	  if(node[p].mx+1==node[q].mx) node[np].par=q,link(np,q);
	  else
	  {
		int nq=++tot;
		node[nq].mx=node[p].mx+1;
		node[nq].par=node[q].par,link(nq,node[q].par);
		cut(q,node[q].par),node[q].par=nq,link(q,nq);
		node[np].par=nq,link(np,nq);
		CPY(node[nq].son,node[q].son);
		while(p&&node[p].son[x]==q)
		    node[p].son[x]=nq,p=node[p].par;
	  }
    }
    last=np;
}

void solve(char *str)
{
    int now=root;
    for(int i=0;str[i];i++)
	  if(node[now].son[str[i]-'A']) now=node[now].son[str[i]-'A'];
	  else{puts("0");return;}
    splay(now);printf("%d\n",val[now]);mask^=val[now];
}

int main()
{
    scanf("%d%s",&m,str+1);
    init();
    for(int i=1;str[i];i++)
	  extend(str[i]-'A');
    while(m--) 
    {
	  scanf("%s%s",opt+1,str);
	  decode(str);
	  if(opt[1]=='Q') solve(str);
	  else for(int i=0;str[i];i++) extend(str[i]-'A');
    }
    return 0;
}    


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值