博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ4963 : String
阅读量:6481 次
发布时间:2019-06-23

本文共 3726 字,大约阅读时间需要 12 分钟。

用SAM支持往末尾在线添加字符的功能。

设$f[i][j]$表示右端点为i的每个左端点的答案,那么当$i$变为$i+1$时,在SAM的parent链形成的树中会新增一个叶子$p$。

对于每个节点,维护它最后一次出现的位置的右端点$v$,那么加入$p$的时候,需要把它到根路径上所有节点的$v$都改为$i+1$,而它们之前的$v$值就是它们倒数第二次出现的位置,可以用$v$来更新答案。

用LCT维护parent树,那么赋值为一种新的颜色可以用access操作实现,经过的每条实链的$v$值都相同。

而在这条实链中,找出最短和最长的子串,那么长度介于它们之间的子串均以$v$结尾作为倒数第二次出现。

对于$f[i+1][]$来说,等价于一段前缀区间取最大值,中间一段贡献一个等差数列,线段树维护即可。

为了在线回答询问,将线段树可持久化即可。

时间复杂度$O(n\log^2n)$。

 

#include
#include
#include
using namespace std;const int N=100010,M=N<<1,E=20000000;int n,m,i,op,x,y,ans;char a[N];int tot=1,last=1,pre[M],son[M][26],ml[M];int T[N],cnt,l[E],r[E],v[E],RT[N],TOT,L[E],R[E],V[E];inline void umin(int&a,int b){ml[a]>ml[b]?(a=b):0;}inline void umax(int&a,int b){a
>1; if(c<=mid)l[y]=change(l[x],a,mid,c,d,p); if(d>mid)r[y]=change(r[x],mid+1,b,c,d,p); return y;}int cal(int x,int a,int b,int c){ if(a==b)return v[x]; int mid=(a+b)>>1; return max(v[x],c<=mid?cal(l[x],a,mid,c):cal(r[x],mid+1,b,c));}int ins(int x,int a,int b,int c,int d){ int y=++TOT; V[y]=max(V[x],d); if(a==b)return y; int mid=(a+b)>>1; if(c<=mid)L[y]=ins(L[x],a,mid,c,d),R[y]=R[x];else L[y]=L[x],R[y]=ins(R[x],mid+1,b,c,d); return y;}int ask(int x,int a,int b,int c,int d){ if(c<=a&&b<=d)return V[x]; int mid=(a+b)>>1,t=0; if(c<=mid)t=ask(L[x],a,mid,c,d); if(d>mid)umax(t,ask(R[x],mid+1,b,c,d)); return t;}inline void modify(int v,int l,int r){ if(!v||l>r)return; RT[n]=ins(RT[n],1,100000,v-r+1,r); T[n]=change(T[n],1,100000,v-r+1,v-l+1,v);}namespace LCT{int f[M],son[M][2],vis[M],tag[M],mi[M],ma[M],a[M];inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}inline void tag1(int x,int p){ if(!x)return; umax(vis[x],p),umax(tag[x],p);}inline void pb(int x){if(tag[x])tag1(son[x][0],tag[x]),tag1(son[x][1],tag[x]),tag[x]=0;}inline void up(int x){ mi[x]=x,ma[x]=ml[x]; if(son[x][0])umin(mi[x],mi[son[x][0]]),umax(ma[x],ma[son[x][0]]); if(son[x][1])umin(mi[x],mi[son[x][1]]),umax(ma[x],ma[son[x][1]]);}inline void rotate(int x){ int y=f[x],w=son[y][1]==x; son[y][w]=son[x][w^1]; if(son[x][w^1])f[son[x][w^1]]=y; if(f[y]){ int z=f[y]; if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x; } f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);}inline void splay(int x){ int s=1,i=x,y;a[1]=i; while(!isroot(i))a[++s]=i=f[i]; while(s)pb(a[s--]); while(!isroot(x)){ y=f[x]; if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);} rotate(x); } up(x);}inline void cut(int x){ splay(x); if(son[x][0])f[son[x][0]]=f[x]; son[x][0]=0; up(x);}inline void access(int x){ for(int y=0;x;y=x,x=f[x]){ splay(x); son[x][1]=0; up(x); modify(vis[x],ml[pre[mi[x]]]+1,ma[x]); tag1(x,n); son[x][1]=y; up(x); }}}inline void ext(int w){ ++n; RT[n]=RT[n-1],T[n]=T[n-1]; int p=++tot,x=last,r,q; for(ml[last=p]=ml[x]+1;x&&!son[x][w];x=pre[x])son[x][w]=p; if(!x)pre[p]=1; else if(ml[x]+1==ml[q=son[x][w]])pre[p]=q; else{ pre[r=++tot]=pre[q];memcpy(son[r],son[q],sizeof son[r]); ml[r]=ml[x]+1; LCT::up(r); LCT::splay(q); LCT::vis[r]=LCT::vis[q]; LCT::f[r]=pre[q]; LCT::cut(q); LCT::f[q]=r; pre[p]=pre[q]=r; for(;x&&son[x][w]==q;x=pre[x])son[x][w]=r; } LCT::up(p); LCT::f[p]=pre[p]; LCT::access(p);}int main(){ scanf("%s",a+1); m=strlen(a+1); for(i=1;i<=m;i++)ext(a[i]-'a'); scanf("%d",&m); while(m--){ scanf("%d",&op); if(op==1){ scanf("%s",a); x=a[0]-'a'; x=((x+ans)%26+26)%26; ext(x); }else{ scanf("%d%d",&x,&y); x=((x-1+ans)%n+n)%n+1; y=((y-1+ans)%n+n)%n+1; if(x>y)swap(x,y); printf("%d\n",ans=max(ask(RT[y],1,100000,x,y),cal(T[y],1,100000,x)-x+1)); } } return 0;}

  

转载地址:http://dsfuo.baihongyu.com/

你可能感兴趣的文章
我的Python学习记录
查看>>
quzatz --Could not load org.quartz.spi.Trigge...
查看>>
qml实现窗口的拖拽效果
查看>>
Centos安装Mysql
查看>>
android Looper 非UI线程中更新UI
查看>>
js if语句多个条件判断
查看>>
AVPacketList结构体和AVPacketQueue结构体
查看>>
PHP操作redis详细讲解
查看>>
Android学习笔记(一)
查看>>
Java 提高篇(一)
查看>>
虚拟化学习笔记
查看>>
浏览器的兼容性问题
查看>>
我的友情链接
查看>>
今天真的搬走了
查看>>
PC散热风扇之研究一:风扇种类介绍
查看>>
关于Session和Cookie简单实例
查看>>
App框架实现———dagger2
查看>>
zabbix 微信报警
查看>>
rsync命令参数及SSH自定义端口远程拷贝
查看>>
通过SQL Server 2008数据库复制实现数据库同步备份
查看>>