題意:一個長度爲n的01串(n<=200000),m次操作,操作包括在某個位置添加一個字符,刪除某個位置的字符,翻轉某個區間的字符串,詢問兩個後綴的LCP。
題解:對於一個靜態的字符串,詢問其兩個後綴的最長LCP,可以用hash+二分的方法,O(lgn)的複雜度求解一次詢問。
此題對字符串有添加、刪除和區間的翻轉的操作,所以我們考慮用splay維護串的hash值。
具體而言,我們維護以這個點爲根的子樹的點的個數和對應串的hash值。對於區間翻轉操作而言,僅僅維護這些值是不行的,我還要維護以這個點爲根的子樹的翻轉串的hash值。
詳情見代碼:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
#include<string.h>
#include<string>
#include<stdlib.h>
typedef long long LL;
typedef unsigned long long LLU;
const int nn=410000;
const int inf=0x3fffffff;
const LL inf64=(LL)inf*inf;
const int mod=1000000007;
using namespace std;
int n,m;
LL po[nn];
char s[nn];
struct node
{
int val;
int cnt;
LL ha;
LL fha;
bool fz;
node* pre;
node* ch[2];
}*root;
void init()
{
po[0]=1;
for(int i=1;i<=400010;i++)
{
po[i]=(po[i-1]*2)%mod;
}
root=NULL;
root=new node;
root->val=0;
root->cnt=2;
root->fz=false;
root->ha=root->fha=0;
root->pre=NULL;
root->ch[0]=root->ch[1]=NULL;
root->ch[1]=new node;
root->ch[1]->val=0;
root->ch[1]->cnt=1;
root->ch[1]->fz=false;
root->ch[1]->ha=root->ch[1]->fha=0;
root->ch[1]->pre=root;
root->ch[1]->ch[0]=root->ch[1]->ch[1]=NULL;
}
inline void push_up(node* o)
{
o->cnt=1;
int lson,rson;
lson=rson=0;
LL lha,rha,lfha,rfha;
lha=rha=lfha=rfha=0;
if(o->ch[0]!=NULL)
{
lha=o->ch[0]->ha;
lfha=o->ch[0]->fha;
o->cnt+=o->ch[0]->cnt;
lson+=o->ch[0]->cnt;
}
if(o->ch[1]!=NULL)
{
rha=o->ch[1]->ha;
rfha=o->ch[1]->fha;
o->cnt+=o->ch[1]->cnt;
rson+=o->ch[1]->cnt;
}
o->ha=lha+(o->val*po[lson])%mod+(rha*po[lson+1])%mod;
o->ha%=mod;
o->fha=rfha+(o->val*po[rson])%mod+(lfha*po[rson+1])%mod;
o->fha%=mod;
}
inline void push_down(node* o)
{
if(o->fz)
{
o->fz=false;
if(o->ch[0]!=NULL)
{
o->ch[0]->fz=!o->ch[0]->fz;
swap(o->ch[0]->ha,o->ch[0]->fha);
swap(o->ch[0]->ch[0],o->ch[0]->ch[1]);
}
if(o->ch[1]!=NULL)
{
o->ch[1]->fz=!o->ch[1]->fz;
swap(o->ch[1]->ha,o->ch[1]->fha);
swap(o->ch[1]->ch[0],o->ch[1]->ch[1]);
}
}
}
void Rotate(node* o)
{
node* x=o->pre;
// push_down(x);
// push_down(o);
int d=(x->ch[0]==o)?0:1;
x->ch[d]=o->ch[d^1];
if(o->ch[d^1]!=NULL)
{
o->ch[d^1]->pre=x;
}
if(x->pre!=NULL)
{
if(x->pre->ch[0]==x)
x->pre->ch[0]=o;
else
x->pre->ch[1]=o;
}
o->pre=x->pre;
o->ch[d^1]=x;
x->pre=o;
push_up(x);
}
void Splay(node* o,node* f)
{
node* x;
node* y;
while(o->pre!=f)
{
if(o->pre->pre==f)
Rotate(o);
else
{
x=o->pre;
y=x->pre;
int d1=(y->ch[0]==x)?0:1;
int d2=(x->ch[0]==o)?0:1;
if(d1==d2)
{
Rotate(x);
Rotate(o);
}
else
{
Rotate(o);
Rotate(o);
}
}
}
push_up(o);
if(f==NULL)
root=o;
}
void select(int k,node* f)
{
node* o=root;
int tem;
while(k)
{
push_down(o);
tem=0;
if(o->ch[0]!=NULL)
tem+=o->ch[0]->cnt;
if(tem>=k)
o=o->ch[0];
else if(tem+1==k)
break;
else
{
o=o->ch[1];
k-=tem+1;
}
}
Splay(o,f);
}
void build(node* &o,node* f,int l,int r)
{
int mid=(l+r)/2;
o=new node;
o->val=s[mid]-'0';
o->cnt=1;
o->ha=o->fha=o->val;
o->fz=false;
o->pre=f;
o->ch[0]=o->ch[1]=NULL;
if(l<=mid-1)
{
build(o->ch[0],o,l,mid-1);
}
if(mid+1<=r)
{
build(o->ch[1],o,mid+1,r);
}
push_up(o);
}
void add(int id,int val)
{
select(id+1,NULL);
select(id+2,root);
root->ch[1]->ch[0]=new node;
root->ch[1]->ch[0]->val=val;
root->ch[1]->ch[0]->cnt=1;
root->ch[1]->ch[0]->ha=root->ch[1]->ch[0]->fha=val;
root->ch[1]->ch[0]->fz=false;
root->ch[1]->ch[0]->pre=root->ch[1];
root->ch[1]->ch[0]->ch[0]=root->ch[1]->ch[0]->ch[1]=NULL;
Splay(root->ch[1]->ch[0],NULL);
}
void san(int id)
{
select(id,NULL);
select(id+2,root);
delete root->ch[1]->ch[0];
root->ch[1]->ch[0]=NULL;
Splay(root->ch[1],NULL);
}
void Reverse(int l,int r)
{
select(l,NULL);
select(r+2,root);
node* &o=root->ch[1]->ch[0];
o->fz=!o->fz;
swap(o->ha,o->fha);
swap(o->ch[0],o->ch[1]);
push_down(o);
Splay(o,NULL);
}
bool check(int len,int L,int R)
{
select(L,NULL);
select(L+len+1,root);
LL ix=root->ch[1]->ch[0]->ha;
select(R,NULL);
select(R+len+1,root);
LL fc=root->ch[1]->ch[0]->ha;
return ix==fc;
}
int solve(int L,int R)
{
int l=0,r=root->cnt-1-R;
int mid;
while(l<r)
{
mid=(l+r+1)/2;
if(check(mid,L,R))
l=mid;
else
r=mid-1;
}
return l;
}
void Clear(node* &o)
{
if(o==NULL)
return ;
Clear(o->ch[0]);
Clear(o->ch[1]);
delete o;
o=NULL;
}
int main()
{
init();
int ix,p1,p2;
while(scanf("%d%d",&n,&m)!=EOF)
{
scanf("%s",s);
select(1,NULL);
build(root->ch[1]->ch[0],root->ch[1],0,n-1);
Splay(root->ch[1]->ch[0],NULL);
while(m--)
{
scanf("%d",&ix);
if(ix==1)
{
scanf("%d%d",&p1,&p2);
add(p1,p2);
}
else if(ix==2)
{
scanf("%d",&p1);
san(p1);
}
else if(ix==3)
{
scanf("%d%d",&p1,&p2);
Reverse(p1,p2);
}
else
{
scanf("%d%d",&p1,&p2);
printf("%d\n",solve(p1,p2));
}
}
select(1,NULL);
select(root->cnt,root);
Clear(root->ch[1]->ch[0]);
Splay(root->ch[1],NULL);
}
return 0;
}