题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3147
题意:给出一个初始长度为n的01串,四种操作:(1)在位置x插入y;(2)删除位置x的内容;(3)翻转区间[L,R]的内容;(4)输出从x开始和从y开始的串的最长公共前缀。
思路:(1)首先,插入、删除和翻转都是基本的splay操作,不再多说;(2)新颖的地方在于这里要查找两个串的最长公共前缀。首先二分这个长度,然后splay中利用哈希记录每个子树的串。然后比如对于查询从x开始长度为len的串的哈希值,只要将x-1和x+len分别调整到根和根的右子树,则根的左子树就是这个串,然后就可以得到其哈希值。值得注意的是,由于有翻转操作,我们保存两个哈希值,一个正的一个反的,翻转时交换就行。
struct node
{
int value,rev,size;
u64 h[2];
node* c[2];
node* p;
};
node a[N],*root,*null;
int tot;
u64 Pow[N];
node* newNode(int value,node *p)
{
node *e=&a[++tot];
e->value=value;
e->size=1;
e->p=p;
e->rev=0;
e->c[0]=e->c[1]=null;
e->h[0]=e->h[1]=value;
return e;
}
void pushDown(node *p)
{
if(p==null) return;
if(p->rev)
{
p->rev=0;
swap(p->c[0],p->c[1]);
swap(p->h[0],p->h[1]);
p->c[0]->rev^=1;
p->c[1]->rev^=1;
}
}
void pushUp(node *p)
{
if(p==null) return;
p->size=p->c[0]->size+p->c[1]->size+1;
p->h[0]=p->c[0]->h[0]*Pow[1+p->c[1]->size]+p->value*Pow[p->c[1]->size]+p->c[1]->h[0];
p->h[1]=p->c[1]->h[1]*Pow[1+p->c[0]->size]+p->value*Pow[p->c[0]->size]+p->c[0]->h[1];
}
void init()
{
tot=0;
null=0;
null=newNode(0,0);
null->size=0;
root=newNode(0,null);
root->c[1]=newNode(0,root);
pushUp(root);
}
void rotate(node *x,int k)
{
node *y=x->p;
pushDown(x->c[0]);
pushDown(x->c[1]);
pushDown(y->c[!k]);
y->c[k]=x->c[!k];
y->c[k]->p=y;
x->p=y->p;
if(y->p->c[0]==y) y->p->c[0]=x;
else y->p->c[1]=x;
y->p=x;
x->c[!k]=y;
pushUp(y);
pushUp(x);
if(root==y) root=x;
}
void splay(node *x,node *y)
{
pushDown(x);
while(x->p!=y)
{
if(x->p->p==y)
{
if(x->p->c[0]==x) rotate(x,0);
else rotate(x,1);
}
else if(x->p->p->c[0]==x->p)
{
if(x->p->c[0]==x) rotate(x->p,0);
else rotate(x,1);
rotate(x,0);
}
else
{
if(x->p->c[1]==x) rotate(x->p,1);
else rotate(x,0);
rotate(x,1);
}
}
}
void select(int k,node *y)
{
node *x=root;
pushDown(x);
while(k!=x->c[0]->size+1)
{
if(k<x->c[0]->size+1) x=x->c[0];
else
{
k-=x->c[0]->size+1;
x=x->c[1];
}
pushDown(x);
}
splay(x,y);
}
void build(int L,int R,int b[],node *p,int side)
{
if(L>R) return;
int mid=(L+R)>>1;
node *x=newNode(b[mid],p);
p->c[side]=x;
build(L,mid-1,b,x,0);
build(mid+1,R,b,x,1);
pushUp(x);
}
void insert(int pos,int cnt,int b[])
{
select(pos+1,null);
select(pos+2,root);
build(1,cnt,b,root->c[1],0);
splay(root->c[1]->c[0],null);
}
void del(int pos,int cnt)
{
select(pos,null);
select(pos+cnt+1,root);
root->c[1]->c[0]=null;
splay(root->c[1],null);
}
void reverse(int pos,int cnt)
{
select(pos,null);
select(pos+cnt+1,root);
root->c[1]->c[0]->rev^=1;
splay(root->c[1]->c[0],null);
}
u64 cal(int x,int y)
{
select(x,null);
select(y+2,root);
return root->c[1]->c[0]->h[0];
}
int b[N],n,m;
int query(int x,int y)
{
int low=0,high=n-y+1,mid;
while(low<=high)
{
mid=(low+high)>>1;
if(cal(x,x+mid-1)==cal(y,y+mid-1)) low=mid+1;
else high=mid-1;
}
if(low<=n-y+1&&cal(x,x+low-1)==cal(y,y+low-1)) return low;
return high;
}
char str[N];
int main()
{
int i;
Pow[0]=1;
FOR1(i,N-1) Pow[i]=Pow[i-1]*7;
Rush(n)
{
RD(m); RD(str+1); init();
FOR1(i,n) b[i]=str[i]-'0';
insert(0,n,b);
int x,y,op;
while(m--)
{
RD(op);
if(op==1) RD(x,b[1]),n++,insert(x,1,b);
else if(op==2) RD(x),n--,del(x,1);
else if(op==3) RD(x,y),reverse(x,y-x+1);
else RD(x,y),printf("%d\n",query(x,y));
}
}
return 0;
}