bzoj 1014 火星人prefix —— splay+hash

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014

用 splay 维护字符串上不同位置的哈希值还是第一次...

具体就是每个节点作为位置被不断旋转,点上维护的哈希值就是此时它及其儿子这一段区间的哈希值;

要查询 LCQ,可以二分一个长度,然后把两端区间分别旋转到根,取出哈希值比较;

据说用模数会很慢,写自然溢出比较好;

因为忘记 rotate 最后要 pushup 而调了很久...注释里是另一种可以A的 rotate - splay 系列;

又加深了对 splay 的理解,它的节点表示位置关系...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
typedef unsigned long long ll;
int const xn=1e5+5,xm=250005;
int n,m,rt,fa[xm],c[xm][2],siz[xm];
ll pw[xm],hsh[xm];
char s[xn],ch[xn];
void pushup(int x)
{
    int ls=c[x][0],rs=c[x][1];
    siz[x]=siz[ls]+siz[rs]+1;
    hsh[x]=hsh[ls]*pw[siz[rs]+1]+(s[x]-'a'+1)*pw[siz[rs]]+hsh[rs];
}
void rotate(int x,int &f)
{
    int y=fa[x],z=fa[y],d=(c[y][1]==x);
    if(z)c[z][c[z][1]==y]=x;
//    if(y==f)f=x; else c[z][c[z][1]==y]=x;
    fa[x]=z; fa[y]=x; fa[c[x][!d]]=y;
    c[y][d]=c[x][!d]; c[x][!d]=y;
    pushup(y); pushup(x);//!!!
}
void splay(int x,int f)//
{
    while(fa[x]!=f)//
    {
        int y=fa[x],z=fa[y];
        if(z!=f)//
        {
            if((c[y][0]==x)^(c[z][0]==y))rotate(x,f);
            else rotate(y,f);
        }
        rotate(x,f);
    }
    if(!f)rt=x;
}
void build(int l,int r,int lst)
{
    if(l>r)return;
    if(l==r)hsh[l]=s[l]-'a'+1,siz[l]=1;
    else build(l,mid-1,mid),build(mid+1,r,mid);
    fa[mid]=lst; c[lst][mid>lst]=mid; pushup(mid);
}
int find(int x,int k)//找到 k 位置
{
     while(1)
     {
         int p=c[x][0],q=c[x][1];
         if(siz[p]+1==k)return x;
         else if(siz[p]+1<k)x=q,k-=siz[p]+1;
         else x=p;
     }
}
void insert(int pos,char d)
{
    s[++n]=d; hsh[n]=d-'a'+1;
    int x=find(rt,pos+1);//+1 因为有左右的'a'
    splay(x,0); x=find(rt,pos+2); splay(x,rt);//
//    splay(x,rt); x=find(rt,pos+2); splay(x,c[rt][1]);
    c[x][0]=n; siz[n]=1; fa[n]=x;
    pushup(x); pushup(rt);
}
void change(int pos,char d)
{
    int x=find(rt,pos+1);
    splay(x,0);//
//    splay(x,rt);
    s[x]=d; pushup(x);
}
bool ck(int l,int r,int k)
{
    ll h1=0,h2=0;
//    int x=find(rt,l); splay(x,rt);//
//    x=find(rt,l+k+1); splay(x,c[rt][1]);
//    x=c[rt][1];//
    int x=find(rt,l); splay(x,0);
    x=find(rt,l+k+1); splay(x,rt);
    h1=hsh[c[x][0]];
//    x=find(rt,r); splay(x,rt);//
//    x=find(rt,r+k+1); splay(x,c[rt][1]);
//    x=c[rt][1];//
    x=find(rt,r); splay(x,0);
    x=find(rt,r+k+1); splay(x,rt);
    h2=hsh[c[x][0]];
    return h1==h2;
}
int query(int x,int l,int r)
{
    int ll=0,rr=n-2-max(l,r)+1,ret=0;
    while(ll<=rr)
    {
        int md=((ll+rr)>>1);
        if(ck(l,r,md))ret=md,ll=md+1;
        else rr=md-1;
    }
    return ret;
}
void init()
{
    n=strlen(s+2); pw[0]=1;
    for(int i=1;i<=xm-5;i++)pw[i]=pw[i-1]*27;
    s[1]=s[n+2]='a'; 
    build(1,n+2,0); n=n+2; rt=(n+1)/2;//
}
int main()
{
    scanf("%s",s+2); init();
    scanf("%d",&m);
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%s%d",ch,&x);
        if(ch[0]=='I')scanf("%s",ch),insert(x,ch[0]);
        if(ch[0]=='R')scanf("%s",ch),change(x,ch[0]);
        if(ch[0]=='Q')scanf("%d",&y),printf("%d\n",query(rt,x,y));
    }
    return 0;
}

 

posted @ 2018-09-29 16:19  Zinn  阅读(181)  评论(0编辑  收藏  举报