本题目的操作是维护01序列。
并需要动态比较序列当前任意两个位置后缀的LCP。
那么只需要用splay维护序列的同时,再维护一个域(当前所在子树01序列的hash值),查找时就可以用伸展树的分裂和合并操作提取所需子树hash值,然后二分即可。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
typedef unsigned long long llu;
#define rep1(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,n) for(int i=0;i<(int)n;i++)
const int maxn = 5e5 + 100;
const llu base = 3137;
llu BA[maxn];
typedef struct node* pointer;
struct node{
pointer ch[2];
int c,flip,v;
llu ha[2];
node(int v=0):v(v){c = 1 ; ha[0]=ha[1]=v; ch[1]=ch[0]=NULL; flip=0;}
int cl(){return ch[0]==NULL ? 0 : ch[0]->c;}
int cr(){return ch[1]==NULL ? 0 : ch[1]->c;}
llu hal(int d){ return ch[0]==NULL ? 0:ch[0]->ha[d];}
llu har(int d){ return ch[1]==NULL ? 0:ch[1]->ha[d];}
int cmp(int x){
if(x == cl() + 1) return -1;
return(cl()>=x ? 0 : 1);
}
void maintain(){
if(ch[0]!=NULL) ch[0]->pushdown();
if(ch[1]!=NULL) ch[1]->pushdown();
ha[0] = (hal(0)*base + v)*BA[cr()] + har(0);
ha[1] = (har(1)*base + v)*BA[cl()] + hal(1);
c = 1 + cl() + cr();
}
void pushdown(){
if(flip){
flip^=1;
swap(ch[0],ch[1]);
swap(ha[0],ha[1]);
if(ch[0]!=NULL) ch[0]->flip^=1;
if(ch[1]!=NULL) ch[1]->flip^=1;
}
}
};
void rotate(pointer& u,int d){
pointer te = u->ch[d^1];
u->ch[d^1] = te->ch[d];
te->ch[d] = u;
u->maintain(); te->maintain();
u = te;
}
void splay(pointer& u,int k){
u->pushdown();
int d = u->cmp(k);
if(d!=-1){
int k2 = (u->cl()>=k ? k : k-u->cl()-1);
pointer te = u->ch[d];
te->pushdown();
int d2 = te->cmp(k2);
if(d2!=-1){
splay(te->ch[d2],d2==0 ? k2 : k2-te->cl()-1);
if(d2 == d) rotate(u , d^1); else rotate(u->ch[d],d2^1);
}
rotate(u , d^1);
}
}
void split(pointer u ,int k , pointer& le ,pointer& ri){
splay(u,k);
le = u;
ri = le->ch[1];
le->ch[1] = NULL;
le->maintain();
}
pointer merge_(pointer le , pointer ri){
splay(le,le->c);
le->ch[1] = ri;
le->maintain();
return le;
}
pointer insert_(pointer u , int p,int v){
pointer le,ri;
split(u,p,le,ri);
le->ch[1]=new node(v);
le->maintain();
return merge_(le,ri);
}
pointer erase_(pointer u, int p){
pointer le,ri;
split(u,p,le,ri);
pointer te = le;
le=le->ch[0];
delete te;
return merge_(le,ri);
}
pointer flip_(pointer u,int p1,int p2){
pointer le,mid,ri,te;
split(u,p1,le,te);
split(te,p2-p1+1,mid,ri);
mid->flip^=1;
return merge_(merge_(le,mid),ri);
}
llu cal(pointer& u,int len,int p){
pointer le,mid,ri,te;
split(u,p,le,te);
split(te,len,mid,ri);
llu tte = mid->ha[0];
u = merge_(merge_(le,mid),ri);
return tte;
}
int judge(pointer& u, int len,int p1,int p2){
return (cal(u,len,p1)==cal(u,len,p2));
}
int find_(pointer& u ,int p1,int p2){
int n = u->c-1;
int l=1,r=n-max(p1,p2)+1;
if(judge(u,r,p1,p2)) return r;
while(l<r){
int m=(l+r)>>1;
if(judge(u,m,p1,p2)) l=m+1;
else r=m;
}
return l-1;
}
int n,Q;
char str[maxn];
pointer root;
void show(pointer u){
u->pushdown();
if(u == NULL) return ;
show(u->ch[0]);
printf("%d",u->v);
show(u->ch[1]);
}
void del(pointer& u){
if(u==NULL) return ;
del(u->ch[0]); del(u->ch[1]);
delete u;
u = NULL;
}
int main()
{
BA[0] = 1;
rep1(i,1,maxn-1) BA[i]=BA[i-1]*base;
while(scanf("%d %d",&n,&Q)==2){
scanf("%s",str);
del(root);
root=NULL;
for(int i=n-1;i>=0;i--) {
pointer te=new node(str[i]-'0');
te->ch[1]=root; root = te;
root->maintain();
}
pointer te=new node(0);
te->ch[1]=root; root = te;
root->maintain();
while(Q--){
int cmd,p1,p2;
scanf("%d %d",&cmd,&p1);
if(cmd!=2) scanf("%d",&p2);
if(cmd==1){
p1++; root = insert_(root,p1,p2);
}
else if(cmd==2){
p1++; root = erase_(root,p1);
}
else if(cmd==3){
root=flip_(root,p1,p2);
}
else {
int ans = find_(root,p1,p2);
printf("%d\n",ans);
}
}
}
return 0;
}
/*
3 10
000
2 1
2 1
2 1
1 0 1
*/