zoukankan      html  css  js  c++  java
  • 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
    ",query(rt,x,y));
        }
        return 0;
    }
  • 相关阅读:
    AC自动机学习笔记(模板)
    codeforces1328E
    Codeforces 1288E- Messenger Simulator (树状数组)
    线性基小记
    HDU3949
    矩阵快速幂小记
    5E
    5D
    5C
    5B
  • 原文地址:https://www.cnblogs.com/Zinn/p/9724346.html
Copyright © 2011-2022 走看看