给一个长度为n的01串,m个操作:
1 p c :在第p位之后插入字符
2 p :删除第p位字符
3 p1 p2: 把从p1到p2位之间的字符翻转
4 p1 p2: 查询以p1,p2开始的字符串的最长公共前缀。
前三个操作可以直接用伸展树处理,查询lcp的话,可以给在每个节点记录一下该子树表示的字符串的hash值,这样在查询的时候就可以二分长度去求lcp了。
因为涉及到翻转操作,所以要求两个hash值,一个正向一个反向,在翻转的时候,直接交换这两个方向的hash值就行。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ull x=233;
const int maxn=502000;
int a[maxn],b[maxn];
char s[maxn];
ull H[2][maxn];
ull xp[maxn];
int size[maxn];
int pre[maxn],ch[maxn][2];
int flip[maxn];
int tot,root;
int n,m;
struct splaytree
{
void init()
{
tot=root=0;
newnode(root,0,0);
newnode(ch[root][1],root,0);
build(1,n,ch[ch[root][1]][0],ch[root][1]);
pushup(ch[root][1]);
pushup(root);
}
void pushup(int r)
{
if (r==0) return;
size[r]=size[ch[r][0]]+1+size[ch[r][1]];
H[1][r]=H[1][ch[r][0]]*xp[1+size[ch[r][1]]]+a[r]*xp[size[ch[r][1]]]+H[1][ch[r][1]];
H[0][r]=H[0][ch[r][0]]+a[r]*xp[size[ch[r][0]]]+H[0][ch[r][1]]*xp[size[ch[r][0]]+1];
}
void go_f(int r)
{
if (!r) return;
flip[r]^=1;
swap(H[0][r],H[1][r]);
swap(ch[r][0],ch[r][1]);
// pushup(r);
}
void pushdown(int r)
{
if (flip[r])
{
go_f(ch[r][0]);
go_f(ch[r][1]);
flip[r]=0;
}
}
void rotate(int xx,int kind)
{
int y=pre[xx];
pushdown(y);
pushdown(xx);
ch[y][!kind]=ch[xx][kind];
pre[ch[xx][kind]]=y;
if (pre[y])
{
ch[pre[y]][ch[pre[y]][1]==y]=xx;
}
pre[xx]=pre[y];
ch[xx][kind]=y;
pre[y]=xx;
pushup(y);
}
void splay(int xx,int tgt)
{
pushdown(xx);
while(pre[xx]!=tgt)
{
int y=pre[xx];
if (pre[pre[xx]]==tgt)
{
rotate(xx,ch[pre[xx]][0]==xx);
}
else
{
int kind=(ch[pre[y]][0]==y);
if (ch[y][kind]==xx)
{
rotate(xx,kind^1);
rotate(xx,kind);
}
else
{
rotate(y,kind);
rotate(xx,kind);
}
}
}
pushup(xx);
if (tgt==0) root=xx;
}
void select(int k,int tgt)
{
int rt=root;
pushdown(rt);
while(true)
{
if (k<=size[ch[rt][0]]) rt=ch[rt][0];
else if (k==size[ch[rt][0]]+1) break;
else k-=(size[ch[rt][0]]+1),rt=ch[rt][1];
pushdown(rt);
}
splay(rt,tgt);
}
void newnode(int &r,int father,int k)
{
r=++tot;
pre[r]=father;
size[r]=1;
flip[r]=0;
a[r]=k;
H[0][r]=H[1][r]=k;
ch[r][0]=ch[r][1]=0;
}
void build(int l,int r,int &xx,int rt)
{
if (l>r) return;
int m=(l+r)>>1;
newnode(xx,rt,b[m]);
build(l,m-1,ch[xx][0],xx);
build(m+1,r,ch[xx][1],xx);
pushup(xx);
pushup(rt);
}
void insert(int posi,int c)
{
select(posi+1,0);
select(posi+2,root);
newnode(ch[ch[root][1]][0],ch[root][1],c);
pushup(ch[root][1]);
pushup(root);
}
void del(int posi)
{
select(posi,0);
select(posi+2,root);
int k=ch[ch[root][1]][0];
pre[k]=0;
ch[ch[root][1]][0]=0;
pushup(ch[root][1]);
pushup(root);
}
ull queryHash(int r,int l)
{
select(r,0);
select(r+l+1,root);
return H[0][ch[ch[root][1]][0]];
}
bool check(int p1,int p2,int l)
{
if (queryHash(p1,l)==queryHash(p2,l)) return true;
return false;
}
int getlcp(int p1,int p2)
{
int ans;
if (!check(p1,p2,1))
{
return 0;
}
ans=1;
int l=1,r=min(size[root]-2-p1+1,size[root]-2-p2+1)+1;
int mid;
while(l<r)
{
mid=(l+r)>>1;
if (check(p1,p2,mid)) ans=mid,l=mid+1;
else r=mid;
}
return ans;
}
void reverse(int p1,int p2)
{
select(p1,0);
select(p2+2,root);
go_f(ch[ch[root][1]][0]);
pushup(ch[root][1]);
pushup(root);
}
void print(int r)
{
if (r==0) return;
pushdown(r);
print(ch[r][0]);
cout<<a[r];
print(ch[r][1]);
}
void traval(int x)
{
if(x)
{
pushdown(x);
traval(ch[x][0]);
printf("结点%2d:左儿子 %2d 右儿子 %2d 父节点 %2d size=%2d ,val=%2d, filp=%2d\n",x,ch[x][0],ch[x][1],pre[x],size[x],a[x],flip[x]);
traval(ch[x][1]);
}
}
void Debug()
{
printf("%d\n",root);
traval(root);
}
}spt;
void reads(int & x)
{
char c;
bool neg=false;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c=='-')
{
neg=true;
while((c=getchar())<'0'||c>'9');
}
x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';
if(neg) x=-x;
}
int main()
{
// freopen("in.txt","r",stdin);
xp[0]=1;
for (int i=1; i<maxn; i++)
xp[i]=xp[i-1]*x;
while(~scanf("%d%d",&n,&m))
{
scanf("%s",s);
for (int i=1; i<=n; i++)
b[i]=s[i-1]-'0';
spt.init();
// spt.traval(root);
// spt.print(root);
// cout<<endl;
int cmd,p1,p2,p3,p4;
while(m--)
{
// scanf("%d",&cmd);
reads(cmd);
if (cmd==1)
{
// scanf("%d%d",&p1,&p2);
reads(p1); reads(p2);
spt.insert(p1,p2);
}
else if (cmd==2)
{
// scanf("%d",&p1);
reads(p1);
spt.del(p1);
}
else if (cmd==3)
{
// scanf("%d%d",&p1,&p2);
reads(p1); reads(p2);
spt.reverse(p1,p2);
// spt.traval(root);
// cout<<p1<<" "<<p2<<endl;
// spt.print(root);
// cout<<endl;
}
else if (cmd==4)
{
// scanf("%d%d",&p1,&p2);
reads(p1); reads(p2);
printf("%d\n",spt.getlcp(p1,p2));
}
}
}
return 0;
}