首页 > 代码库 > bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)

bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)

  题目大意:一个字符串三个操作:①求两个后缀的LCP②插入一个字符③修改一个字符。

  前几天刚学了hash+二分求lcp,就看到这题。

  原来splay还能这么用?!原来splay模板这么好写?我以前写的splay是假的吧woc

  splay每个节点代表一个字符,并维护这个子树代表一个子串的哈希值。因为splay旋转不破坏树结构,所以不论怎么旋转这棵splay树都能代表这个字符串。

  预处理处理少了调了半天呜呜呜

  赶紧跑去更新自己的splay模板

技术分享
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#define which(x) (son[fa[x]][1]==x)
#define ull unsigned long long
using namespace std;
const int maxn=500010;
int n,m,x,y,tot,root;
int fa[maxn],son[maxn][2],size[maxn],s[maxn];
ull hs[maxn],mul[maxn];
char st[maxn],ch[maxn],ch2[maxn];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;    
}
void update(int x)
{
    size[x]=size[son[x][0]]+size[son[x][1]]+1;
    hs[x]=hs[son[x][0]]+mul[size[son[x][0]]]*s[x]+mul[size[son[x][0]]+1]*hs[son[x][1]];
}
void rotate(int x)
{
    int f=fa[x];
    bool k=which(x);
    son[f][k]=son[x][!k];
    son[x][!k]=f;
    son[fa[f]][which(f)]=x;
    fa[son[f][k]]=f;
    fa[x]=fa[f];
    fa[f]=x;
    size[x]=size[f];
    hs[x]=hs[f];
    update(f);
}
void splay(int x,int g)
{
    while(fa[x]!=g)
    {
        int f=fa[x];
        if(fa[f]==g)
        {
            rotate(x);
            break;
        }
        if(which(x)^which(f))rotate(x);
        else rotate(f);
        rotate(x);
    }
    if(!g)root=x;
}
int rank(int x,int k)
{
    if(k<=size[son[x][0]])return rank(son[x][0],k);
    else if(k==(size[son[x][0]]+1))return x;
    else return rank(son[x][1],k-size[son[x][0]]-1);
}
int build(int l,int r,int f)
{
    if(l>r)return 0;
    int x=++tot,mid=(l+r)>>1;
    fa[x]=f;s[x]=(int)(st[mid]-a)+1;
    son[x][0]=build(l,mid-1,x);
    son[x][1]=build(mid+1,r,x);
    update(x);
    return x;
}
void insert(int k,int ch)
{
    int x=rank(root,k),y=rank(root,k+1);
    splay(x,0);splay(y,x);
    s[++tot]=ch;
    fa[tot]=y;son[y][0]=tot;
    update(tot);update(y);update(x);
}
void change(int k,int ch)
{
    int x=rank(root,k);
    splay(x,0);
    s[x]=ch;
    update(x);
}
int lcp(int kx,int ky)
{
    int l=0,r=n;
    while(l<r)
    {
        int mid=(l+r+1)>>1;
        if(ky+mid>n+2)
        {
            r=mid-1;
            continue;
        }
        int x=rank(root,kx-1),y=rank(root,kx+mid);
        splay(x,0);splay(y,x);
        ull haxi=hs[son[y][0]];
        x=rank(root,ky-1),y=rank(root,ky+mid);
        splay(x,0);splay(y,x);
        if(haxi==hs[son[y][0]])l=mid;
        else r=mid-1;
    }
    return l;
}
int main()
{
    scanf("%s",st+1);
    n=strlen(st+1);
    mul[0]=1;
    for(int i=1;i<=150010;i++)mul[i]=mul[i-1]*27;
    root=build(0,n+1,0);
    read(m);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",ch);
        if(ch[0]==Q)
        {
            read(x);read(y);
            if(x>y)swap(x,y);
            if(x!=y)printf("%d\n",lcp(x+1,y+1));
            else printf("%d\n",n-x+1);
        }
        if(ch[0]==R)
        {
            read(x);
            scanf("%s",ch2);
            change(x+1,(int)(ch2[0]-a)+1);
        }
        if(ch[0]==I)
        {    
            read(x);
            scanf("%s",ch2);
            insert(x+1,(int)(ch2[0]-a)+1);
            n++;
        }
    }
    return 0;
}
View Code

 

bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)