【伸展树(splay)】[JSOI2008][HYSBZ/BZOJ1014]火星人prefix
题目链接
分析
这道题有修改操作,显然不能使用后缀数组等数据结构。
我们可以用hash值来判断两个字符串是否相同,所以,我们可以用splay来维护出以当前字符为根的字符串的hash值,二分长度来求出LCQ(x,y)的值。
代码
这是top-down的splay
#include<cstdio>
#include<algorithm>
#include<cstring>
#define P 67
#define MOD 1000000007
using namespace std;
#define MAXN 100000
int hash_pow[MAXN+10],m,n;
char s[MAXN+10];
void Read(int &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
struct node{
int size,val,h;
node *ch[2];
}tree[MAXN+10],*tcnt=tree,*nil=tree,*root=nil;
void init(node *x){
x->val=x->size=x->h=0;
x->ch[0]=x->ch[1]=nil;
}
inline void update(node *p){
p->size=p->ch[0]->size+p->ch[1]->size+1;
p->h=((1ll*p->ch[0]->h*P+p->val)%MOD*hash_pow[p->ch[1]->size]%MOD+p->ch[1]->h)%MOD;
}
void single_Rotate(bool d){
node *x=root->ch[!d];
root->ch[!d]=nil->ch[!d];
nil->ch[!d]=root;
root=x;
}
void double_Rotate(bool d){
node *x=root->ch[!d],*y=x->ch[!d];
root->ch[!d]=x->ch[d];
x->ch[d]=root;
x->ch[!d]=nil->ch[!d];
nil->ch[!d]=x;
update(root);
root=y;
}
void finish(){
node *x,*y;
for(int d=0;d<2;d++){
x=nil->ch[!d];
while(x!=nil){
y=x->ch[!d];
x->ch[!d]=root->ch[d];
root->ch[d]=x;
update(x);
x=nil->ch[!d]=y;
}
}
update(root);
}
template<class T>
void search_pos(T pos){
bool d,dd;
node *x;
while(root!=nil){
if(root->ch[0]->size+1==pos)
return;
if(pos<root->ch[0]->size+1)
d=1;
else
d=0,pos-=root->ch[0]->size+1;
x=root->ch[!d];
if(x==nil||x->ch[0]->size+1==pos){
single_Rotate(d);
return;
}
if(pos<x->ch[0]->size+1)
dd=1;
else
dd=0,pos-=x->ch[0]->size+1;
if(d==dd)
double_Rotate(d);
else
single_Rotate(d),single_Rotate(dd);
}
}
void read(){
scanf("%s",s);
n=strlen(s);
init(nil);
for(int i=0;i<n;i++){
single_Rotate(0);
init(root=++tcnt);
root->val=s[i]-'a'+1;
}
finish();
}
inline int Get_hash(int pos){
if(pos>root->size)
return 0;
search_pos(pos);
finish();
return (1ll*root->val*hash_pow[root->ch[1]->size]%MOD+root->ch[1]->h)%MOD;
}
bool check(int x,int y,int len){
int a,b;
a=((Get_hash(x)-Get_hash(x+len))%MOD+MOD)%MOD;
b=(1ll*(Get_hash(y)-Get_hash(y+len))%MOD*hash_pow[y-x]%MOD+MOD)%MOD;
return a==b;
}
int partition(int x,int y,int l,int r){
int mid;
while(l<r){
mid=(l+r+1)>>1;
if(check(x,y,mid))
l=mid;
else
r=mid-1;
}
return l;
}
void repla(int pos,int val){
search_pos(pos);
root->val=val;
finish();
}
void insert(int pos,int val){
search_pos(pos+0.5);
init(root=++tcnt);
root->val=val;
finish();
}
void solve(){
Read(m);
char c[20];
int x,y;
while(m--){
scanf("%s",c);
if(c[0]=='Q'){
Read(x),Read(y);
if(x>y)
swap(x,y);
printf("%d\n",partition(x,y,0,root->size-y+1));
}
else if(c[0]=='R'){
Read(x),scanf("%s",c);
repla(x,c[0]-'a'+1);
}
else{
Read(x),scanf("%s",c);
insert(x,c[0]-'a'+1);
}
}
}
void prepare(){
hash_pow[0]=1;
for(int i=1;i<=MAXN;i++)
hash_pow[i]=1ll*hash_pow[i-1]*P%MOD;
}
int main()
{
prepare();
read();
solve();
}