题意:
给字符串
S
S
,支持:
1.末尾加入字符。
2.查询中出现两次的最长字符串。
题解:
好题。
考虑离线做法:
动态插入后面的字符,更新前面
l
l
的答案。
当我们插入一个字符的时候,与前面的公共子串为它的后缀。 我们考虑暴力跳
fail
f
a
i
l
链来更新答案:
每个位置记last表示endpos的最后一个位置,那么这个位置能更新
i−len[i]+1
i
−
l
e
n
[
i
]
+
1
往左的
l
l
,以及的l。 其中第一部分的答案为
len[i]
l
e
n
[
i
]
,第二部分则为
len[i]−(p−(i−len[i]+1))
l
e
n
[
i
]
−
(
p
−
(
i
−
l
e
n
[
i
]
+
1
)
)
。 我们分别在线段树上维护两个
tag
t
a
g
即可。
发现这个覆盖过程就是 lct l c t 的 access a c c e s s ,那么我们用lct来维护这个last即可。(均摊 O(nlogn) O ( n log n ) ,想不到字符串有这么优美的性质)
同样,在线的话把线段树可持久化就行了。
#include <bits/stdc++.h>
#include <tr1/unordered_map>
using namespace std;
typedef long long LL;
typedef pair <int,int> pii;
typedef unsigned long long ULL;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
inline void W(int x) {
static int buf[50];
if(!x) {putchar('0'); return;}
if(x<0) {putchar('-'); x=-x;}
while(x) {buf[++buf[0]]=x%10; x/=10;}
while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}
const int N=2e5+50, INF=0x3f3f3f3f, lg=200;
int n;
namespace sgt {
int lc[N*lg],rc[N*lg],mx[N*lg],mxa[N*lg],rt[N],tot;
inline void copy(int &x,int y) {
x=++tot; lc[x]=lc[y]; rc[x]=rc[y]; mx[x]=mx[y]; mxa[x]=mxa[y];
}
inline void modify(int &y,int x,int l,int r,int L,int R,int v) {
if(L>R) return;
copy(y,x);
if(l==L&&r==R) {mx[y]=max(mx[y],v); return;}
int mid=(l+r)>>1;
if(R<=mid) modify(lc[y],lc[x],l,mid,L,R,v);
else if(L>mid) modify(rc[y],rc[x],mid+1,r,L,R,v);
else modify(lc[y],lc[x],l,mid,L,mid,v), modify(rc[y],rc[x],mid+1,r,mid+1,R,v-(mid+1-L));
}
inline void modifya(int &y,int x,int l,int r,int L,int R,int v) {
copy(y,x);
if(L<=l&&r<=R) {mxa[y]=max(mxa[y],v); return;}
int mid=(l+r)>>1;
if(R<=mid) modifya(lc[y],lc[x],l,mid,L,R,v);
else if(L>mid) modifya(rc[y],rc[x],mid+1,r,L,R,v);
else modifya(lc[y],lc[x],l,mid,L,R,v), modifya(rc[y],rc[x],mid+1,r,L,R,v);
}
inline int ask(int x,int l,int r,int p) {
if(!x) return -INF;
int rs=max(mx[x]-p+l,mxa[x]);
if(l==r) return rs;
int mid=(l+r)>>1;
if(p<=mid) rs=max(rs, ask(lc[x],l,mid,p));
else rs=max(rs, ask(rc[x],mid+1,r,p));
return rs;
}
inline int ask(int l,int r) {
return ask(rt[r],1,n,l);
}
}
namespace lct {
struct node {
node *lc,*rc,*fa;
int last;
node() : lc(NULL),rc(NULL),fa(NULL){}
}Pool[N];
inline bool isroot(node *x) {return (!x->fa) || (x->fa->lc!=x && x->fa->rc!=x);}
inline bool which(node *x) {return x->fa->lc==x;}
inline void rotate(node *x) {
node *y=x->fa, *z=y->fa;
if(!isroot(y)) (z->lc==y ? z->lc : z->rc)=x;
x->fa=z; y->fa=x;
if(y->lc==x) {
node *b=x->rc;
x->rc=y; y->lc=b;
if(b) b->fa=y;
} else {
node *b=x->lc;
x->lc=y; y->rc=b;
if(b) b->fa=y;
}
}
inline void splay(int p) {
static node* stk[N];
node *x=p+Pool;
int tl; stk[tl=1]=x;
for(node *y=x; !isroot(y); y=y->fa) stk[++tl]=y->fa;
for(int i=tl-1;i;i--) stk[i]->last=stk[i+1]->last;
while(!isroot(x)) {
node *y=x->fa;
if(!isroot(y)) {
if(which(x)==which(y)) rotate(y);
else rotate(x);
} rotate(x);
}
}
inline void link(int p,int q) {
node *x=Pool+p, *y=Pool+q;
splay(p); x->fa=y;
}
inline void cut(int p,int q) {
node *x=Pool+p, *y=Pool+q;
splay(p); x->fa=NULL;
}
inline void access(int &x,int p,int pos,int *len) {
node *t=(Pool+p);
for(node *y=NULL; t; y=t, t=t->fa) {
splay(t-Pool);
if(t->last && t->last<pos) {
sgt::modify(x,x,1,n,t->last-len[t-Pool]+1,t->last,len[t-Pool]);
sgt::modifya(x,x,1,n,1,t->last-len[t-Pool]+1,len[t-Pool]);
}
if(t->rc) t->rc->last=t->last;
t->rc=y; t->last=pos;
}
}
}
namespace sam {
int son[N][26],tot=1,l[N],fail[N],lst=1;
inline void extend(int c,int pos) {
sgt::rt[pos]=sgt::rt[pos-1];
int p=++tot; l[p]=l[lst]+1;
(lct::Pool+p)->last=pos;
while(lst && !son[lst][c]) son[lst][c]=p, lst=fail[lst];
if(!lst) fail[p]=1, lct::link(p,1);
else {
int q=son[lst][c];
if(l[q]==l[lst]+1) fail[p]=q,lct::link(p,q);
else {
int np=++tot; fail[np]=fail[q]; l[np]=l[lst]+1;
memcpy(son[np],son[q],sizeof(son[np]));
fail[np]=fail[q]; fail[q]=fail[p]=np;
while(lst && son[lst][c]==q) son[lst][c]=np, lst=fail[lst];
(lct::Pool+np)->last=(lct::splay(q),(lct::Pool+q)->last);
lct::access(sgt::rt[pos],fail[np],pos,l);
lct::cut(q,fail[np]);
lct::link(np,fail[np]);
lct::link(q,np);
lct::link(p,np);
}
}
lct::access(sgt::rt[pos],p,pos,l);
lst=p;
}
}
char ch[N]; int len,type,la;
int main() {
sgt::mx[0]=sgt::mxa[0]=-INF;
scanf("%d%s",&type,ch+1);
len=strlen(ch+1);
int m=rd(); n=len+m;
for(int i=1;i<=len;i++)
sam::extend(ch[i]-'a',i);
for(int i=m;i;i--) {
int op=rd();
if(op==1) {
ch[++len]=(nc()-'a'+la*type)%26+'a';
sam::extend(ch[len]-'a',len);
} else {
int l=(rd()-1+la*type)%len+1, r=(rd()-1+la*type)%len+1;
W(la=max(sgt::ask(l,r),0)); putchar('\n');
}
}
}