[BZOJ1014][JSOI2008]火星人prefix:Splay+Hash+二分答案

分析:

类似于Splay维护序列,Splay的每个节点维护其子树所表示字符串的哈希值。
询问时二分答案即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
typedef long long LL;

inline int read(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x;
}

const int MAXN=100005;
const LL MOD=998244353;
const LL Base=31;
char str[MAXN];
int m,root,tot;
LL pw[MAXN];
struct Splay{
    int ch[2],fa;
    int val;
    int siz;
    LL hsh;
}a[MAXN];

inline void pre_process(){
    pw[0]=1;
    for(int i=1;i<=MAXN-1;i++)
        pw[i]=pw[i-1]*Base;
}

#define lc a[x].ch[0]
#define rc a[x].ch[1]
inline void pushup(int x){
    a[x].siz=a[lc].siz+a[rc].siz+1;
    a[x].hsh=a[rc].hsh+a[x].val*pw[a[rc].siz]+a[lc].hsh*pw[a[rc].siz+1];
}

int build(int l,int r,int pre){
    if(l>r) return 0;
    int x=++tot;
    int mid=((l+r)>>1);
    a[x].fa=pre;
    a[x].val=str[mid]-'a';
    lc=build(l,mid-1,x);
    rc=build(mid+1,r,x);
    pushup(x);
    return x;
}

inline void rotate(int x){
    int y=a[x].fa,z=a[y].fa,f=(a[y].ch[1]==x),g=a[x].ch[f^1];
    if(z) a[z].ch[a[z].ch[1]==y]=x;
    a[x].ch[f^1]=y;
    a[y].ch[f]=g;
    if(g) a[g].fa=y;
    a[y].fa=x;
    a[x].fa=z;
    pushup(y);
    pushup(x);
}

inline void splay(int x,int tp){
    while(a[x].fa!=tp){
        int y=a[x].fa,z=a[y].fa;
        if(a[y].fa!=tp){
            if((a[y].ch[0]==x)==(a[z].ch[0]==y)) rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
    if(tp==0) root=x;
}

inline int kth(int k){
    int x=root;
    while(1){
        if(a[lc].siz>=k) x=lc;
        else if(a[lc].siz+1==k) return x;
        else{
            k-=a[lc].siz+1;
            x=rc;
        }
    }
}

inline LL query(int x,int y){
//  std::cout<<x<<" "<<y<<std::endl;
    int xx=kth(x-1),yy=kth(y+1);
    splay(xx,0);
    splay(yy,xx);
    return a[a[yy].ch[0]].hsh;
}

inline int lcq(int x,int y){
    if(x<y) std::swap(x,y);
    int l=0,r=tot-x,ret=0;
    while(l<=r){
//      std::cout<<l<<" "<<r<<std::endl;
        int mid=((l+r)>>1);
        if(query(x,x+mid-1)==query(y,y+mid-1)) ret=mid,l=mid+1;
        else r=mid-1;
    }
    return ret;
}

inline void upd(int x,int ch){
    int xx=kth(x);
    splay(xx,0);
    a[xx].val=ch;
    pushup(xx);
}

inline void ins(int x,int ch){
    int xx=kth(x),yy=kth(x+1);
    splay(xx,0);
    splay(yy,xx);
    a[yy].ch[0]=++tot;
    a[tot].fa=yy;
    a[tot].val=ch;
//...
    splay(tot,0);
}

void write(int x){
    if(lc) write(lc);
    std::cout<<char(a[x].val+'a'==0?'#':a[x].val+'a');
    if(rc) write(rc);
}

int main(){
    pre_process();
    scanf("%s",str+2);
    int len=strlen(str+2);
    len+=2;
//  std::cout<<len<<std::endl;
//  std::cout<<str[2]<<" "<<str[12]<<std::endl;
    str[1]=str[len]='\0';
    root=build(1,len,0);
    scanf("%d",&m);
    while(m--){
//      write(root);std::cout<<std::endl;
        char opt=getchar();
        while(!isalpha(opt)) opt=getchar();
        if(opt=='Q'){
            int x=read(),y=read();
            printf("%d\n",lcq(x+1,y+1));
        }
        else if(opt=='R'){
            int x=read();char ch=getchar();
            while(!isalpha(ch)) ch=getchar();
            upd(x+1,ch-'a');
        }
        else{
            int x=read();char ch=getchar();
            while(!isalpha(ch)) ch=getchar();
            ins(x+1,ch-'a');
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9745977.html
今日推荐