• bzoj1014: [JSOI2008]火星人prefix


    我TM的怕不是个傻逼。。check里面比较hash搞成比较c,居然还能过数据,还过了n个对拍。。果然假如考试信样例就有鬼了。

    嗯隔壁哈老师告诉我,hash其实不用mod,直接自然溢出就行,get到新姿势。

    这道题前两个操作明显可以用伸展树来解决,问题在于比较两个后缀的前缀,那我们的做法就是令伸展树记录一个h表示当前子树的hash,那我们通过比较hash就可以方便的知道,两个子串是否相等,那比较后缀时,就用二分枚举匹配长度,然后比较hash就行了、

    #include<cstdio>
    #include<cstring>
    using namespace std;
    int mi[110000];
    struct node
    {
        int f,c,h,hash,son[2];//hash表示以当前节点管理的节点的hash值 
    }tr[110000];int root,len;
    void update(int x)
    {
        int lc=tr[x].son[0],rc=tr[x].son[1];
        tr[x].c=tr[lc].c+tr[rc].c+1;
        tr[x].hash=tr[lc].hash*mi[tr[rc].c+1] + tr[x].h*mi[tr[rc].c] + tr[rc].hash;
    }
    void rotate(int x,int w)
    {
        int f=tr[x].f,ff=tr[f].f;
        int r,R;
        
        r=tr[x].son[w];R=f;
        tr[R].son[1-w]=r;
        if(r!=0)tr[r].f=R;
        
        r=x;R=ff;
        if(tr[ff].son[0]==f)tr[R].son[0]=r;
        else                 tr[R].son[1]=r;
        tr[r].f=R;
        
        r=f;R=x;
        tr[R].son[w]=r;
        tr[r].f=R;
        
        update(f);
        update(x);
    }
    void splay(int x,int rt)
    {
        while(tr[x].f!=rt)
        {
            int f=tr[x].f,ff=tr[f].f;
            if(ff==rt)
            {
                if(x==tr[f].son[0])rotate(x,1);
                else                rotate(x,0);
            }
            else
            {
                     if(tr[f].son[0]==x&&tr[ff].son[0]==f){rotate(f,1);rotate(x,1);}
                else if(tr[f].son[1]==x&&tr[ff].son[0]==f){rotate(x,0);rotate(x,1);}
                else if(tr[f].son[0]==x&&tr[ff].son[1]==f){rotate(x,1);rotate(x,0);}
                else if(tr[f].son[1]==x&&tr[ff].son[1]==f){rotate(f,0);rotate(x,0);}
            }
        }
        if(rt==0)root=x;
    }
    void ins(int h,int f)
    {
        len++;
        tr[len].c=1;tr[len].h=h;
        tr[len].hash=h;
        tr[len].son[0]=tr[len].son[1]=0;
        
        if(f==0){tr[len].f=0;root=len;}
        else
        {
            splay(f,0);
            if(tr[f].son[1]==0)
            {
                tr[len].f=f;
                tr[f].son[1]=len;
            }
            else
            {
                f=tr[f].son[1];
                while(tr[f].son[0]!=0)f=tr[f].son[0];
                
                tr[len].f=f;
                tr[f].son[0]=len;
            }
            splay(f,0);
        }
    }
    int findweizhi(int k)
    {
        int x=root;
        while(x!=0)
        {
            int d=tr[tr[x].son[0]].c+1;
                 if(k<d) x=tr[x].son[0];
            else if(d<k){x=tr[x].son[1];k-=d;}
            else break;
        }
        return x;
    }
    void change(int x,int h)
    {
        splay(x,0);
        tr[x].h=h;
        update(x);
    }
    bool check(int x,int y,int mid)
    {
        int xl=findweizhi(x),xr=findweizhi(x+mid-1);
        int yl=findweizhi(y),yr=findweizhi(y+mid-1);
        
        if(tr[xl].h!=tr[yl].h||tr[xr].h!=tr[yr].h)return false;
        
        if(mid<=2)return true;
    
        int hx,hy;
        
        splay(xl,0);splay(xr,xl);
        hx=tr[tr[xr].son[0]].hash;
        
        splay(yl,0);splay(yr,yl);
        hy=tr[tr[yr].son[0]].hash;
        
        if(hx==hy)return true;
        return false;
    }
    char ss[110000];
    int main()
    {
        freopen("hehe.in","r",stdin);
        freopen("w.out","w",stdout);
        mi[0]=1;for(int i=1;i<=100000;i++)mi[i]=mi[i-1]*27;
        root=len=0;ins(0,0);
        scanf("%s",ss+1);int slen=strlen(ss+1);
        for(int i=1;i<=slen;i++)ins(int(ss[i]-'a'+1),len);
        
        int m,x,y;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",ss+1);
            if(ss[1]=='R')
            {
                scanf("%d%s",&x,ss+1);
                x=findweizhi(x+1);
                change(x,int(ss[1]-'a'+1));
            }
            else if(ss[1]=='I')
            {
                scanf("%d%s",&x,ss+1);
                x=findweizhi(x+1);
                ins(int(ss[1]-'a'+1),x);
            }
            else
            {
                scanf("%d%d",&x,&y);x++;y++;
                if(x>y){int t=x;x=y;y=t;}
                
                int l=1,r=len-y+1,ans=0;
                while(l<=r)
                {
                    int mid=(l+r)/2;
                    if(check(x,y,mid)==true)
                    {
                        l=mid+1;
                        ans=mid;
                    }
                    else r=mid-1;
                }
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    笛卡尔树学习笔记
    图论基础(自认为很全)
    我的博客在这里
    C++学习资料
    test
    个人介绍
    CF1153F Serval and Bonus Problem
    【ZJOI2020】抽卡
    【LOJ】小 Q 的序列
    我的个人博客:https://xyix.github.io
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/7640129.html
Copyright © 2020-2023  润新知