【伸展树(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();
}

你可能感兴趣的:(数据结构,C++,hash,splay,JSOI)